Generic write mode 0 function was missing set/reset capability

This commit is contained in:
Jeff Parsons 2015-06-27 10:31:26 -07:00
commit a0d89e5071
7 changed files with 121 additions and 112 deletions

View file

@ -690,7 +690,7 @@ CPU.prototype.calcCycles = function(fRecalc)
*/
CPU.prototype.getCycles = function(fScaled)
{
var nCycles = this.nTotalCycles + this.nRunCycles + this.nBurstCycles - this.nStepCycles;
var nCycles = (this.nTotalCycles + this.nRunCycles + this.nBurstCycles - this.nStepCycles)|0;
if (fScaled && this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz > this.aCounts.mhzDefault) {
/*
* We could scale the current cycle count by the current effective speed (this.aCounts.mhz); eg:
@ -787,10 +787,11 @@ CPU.prototype.getSpeedTarget = function()
/**
* setSpeed(nMultiplier, fOnClick)
*
* NOTE: This used to return the target speed, in mhz, but no callers appear to care at this point.
*
* @this {CPU}
* @param {number} [nMultiplier] is the new proposed multiplier (reverts to 1 if the target was too high)
* @param {boolean} [fOnClick] is true if called from a click handler that might have stolen focus
* @return {number} the target speed, in mhz
* @desc Whenever the speed is changed, the running cycle count and corresponding start time must be reset,
* so that the next effective speed calculation obtains sensible results. In fact, when runCPU() initially calls
* setSpeed() with no parameters, that's all this function does (it doesn't change the current speed setting).
@ -819,7 +820,6 @@ CPU.prototype.setSpeed = function(nMultiplier, fOnClick)
this.aCounts.msStartRun = usr.getTime();
this.aCounts.msEndThisRun = 0;
this.calcCycles();
return this.aCounts.mhzTarget;
};
/**

View file

@ -1677,6 +1677,19 @@ Card.ACCESS.readByteMode1 = function readByteMode1(off, addr)
/**
* writeByteMode0(off, b, addr)
*
* Supporting Set/Reset means that for every plane for which Set/Reset is enabled, we must
* replace the corresponding byte in "dw" with a byte of zeros or ones. This is accomplished with
* nSetMapMask, nSetMapData, and nSetMapBits. nSetMapMask is the inverse of the ESRESET bits,
* because we use it to mask the processor data; nSetMapData records the desired SRESET bits; and
* nSetMapBits contains the bits to replace those that we masked in the processor data.
*
* We could have done this:
*
* dw = (dw & this.controller.nSetMapMask) | (this.controller.nSetMapData & ~this.controller.nSetMapMask)
*
* but by maintaining nSetMapBits equal to (nSetMapData & ~nSetMapMask), we are able to make the writes
* slightly more efficient.
*
* @this {Memory}
* @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
@ -1686,7 +1699,8 @@ Card.ACCESS.writeByteMode0 = function writeByteMode0(off, b, addr)
{
var idw = off + this.offset;
var dw = b | (b << 8) | (b << 16) | (b << 24);
dw = (this.adw[idw] & ~this.controller.nWriteMapMask) | (dw & this.controller.nWriteMapMask);
dw = (dw & this.controller.nSetMapMask) | this.controller.nSetMapBits;
dw = (dw & this.controller.nWriteMapMask) | (this.adw[idw] & ~this.controller.nWriteMapMask);
dw = (dw & this.controller.nBitMapMask) | (this.controller.latches & ~this.controller.nBitMapMask);
if (this.adw[idw] != dw) {
this.adw[idw] = dw;
@ -1723,19 +1737,6 @@ Card.ACCESS.writeByteMode0EvenOdd = function writeByteMode0EvenOdd(off, b, addr)
/**
* writeByteMode0Rot(off, b, addr)
*
* Supporting Set/Reset means that for every plane for which Set/Reset is enabled, we must
* replace the corresponding byte in "dw" with a byte of zeros or ones. This is accomplished with
* nSetMapMask, nSetMapData, and nSetMapBits. nSetMapMask is the inverse of the ESRESET bits,
* because we use it to mask the processor data; nSetMapData records the desired SRESET bits; and
* nSetMapBits contains the bits to replace those that we masked in the processor data.
*
* We could have done this:
*
* dw = (dw & this.controller.nSetMapMask) | (this.controller.nSetMapData & ~this.controller.nSetMapMask)
*
* but by maintaining nSetMapBits equal to (nSetMapData & ~nSetMapMask), we are able to make the writes
* slightly more efficient.
*
* @this {Memory}
* @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
@ -5062,7 +5063,11 @@ Video.prototype.getRetraceBits = function(card)
*/
var nCycles = this.cpu.getCycles();
var nElapsedCycles = nCycles - card.nInitCycles;
if (nElapsedCycles < 0) nElapsedCycles = 0; // TODO: Determine if this ever happens
if (nElapsedCycles < 0) {
this.assert(nCycles === 0);
card.nInitCycles = nElapsedCycles;
nElapsedCycles = -nElapsedCycles|0;
}
var nCyclesHorzRemain = nElapsedCycles % card.nCyclesHorzPeriod;
if (nCyclesHorzRemain > card.nCyclesHorzActive) b |= Card.CGA.STATUS.DISP_RETRACE;
var nCyclesVertRemain = nElapsedCycles % card.nCyclesVertPeriod;
@ -5076,7 +5081,7 @@ Video.prototype.getRetraceBits = function(card)
*
* NOTE: Now that we're calling getRetraceBits() more frequently (ie, for internal checks), resetting nInitCycles
* in this fashion preserves the vertical period at the expense of the horizontal period, which in turn can cause
* grief in ROM BIOS code that requires strict horizontal retrace times. So the above code is now disabled.
* grief in ROM BIOS code that requires strict horizontal retrace times. TODO: Figure out how to re-enable this code.
*/
return b;
};

View file

@ -166,7 +166,7 @@ function X86CPU(parmsCPU)
* A variety of stepCPU() state variables that don't strictly need to be initialized before the first
* stepCPU() call, but it's good form to do so.
*/
this.nBurstCycles = 0;
this.resetCycles();
this.aFlags.fComplete = this.aFlags.fDebugCheck = false;
/*

View file

@ -15,39 +15,39 @@ VIDEO_SEGMENT equ 0a000h ;display memory segment for
LOGICAL_SCREEN_WIDTH equ 672/8 ;width in bytes and height in scan
LOGICAL_SCREEN_HEIGHT equ 384 ; lines of the virtual screen
; we'll work with
PAGE0 equ 0 ;flag for page 0 when page flipping
PAGE1 equ 1 ;flag for page 1 when page flipping
PAGE0_OFFSET equ 0 ;start offset of page 0 in VGA memory
PAGE0 equ 0 ;flag for page 0 when page flipping
PAGE1 equ 1 ;flag for page 1 when page flipping
PAGE0_OFFSET equ 0 ;start offset of page 0 in VGA memory
PAGE1_OFFSET equ LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT
;start offset of page 1 (both pages
; are 672x384 virtual screens)
BALL_WIDTH equ 24/8 ;width of ball in display memory bytes
BALL_HEIGHT equ 24 ;height of ball in scan lines
BLANK_OFFSET equ PAGE1_OFFSET * 2 ;start of blank image
; in VGA memory
;start offset of page 1 (both pages
; are 672x384 virtual screens)
BALL_WIDTH equ 24/8 ;width of ball in display memory bytes
BALL_HEIGHT equ 24 ;height of ball in scan lines
BLANK_OFFSET equ PAGE1_OFFSET * 2;start of blank image
; in VGA memory
BALL_OFFSET equ BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT)
;start offset of ball image in VGA memory
NUM_BALLS equ 4 ;number of balls to animate
;start offset of ball image in VGA memory
NUM_BALLS equ 4 ;number of balls to animate
;
; VGA register equates.
;
SC_INDEX equ 3c4h ;SC index register
MAP_MASK equ 2 ;SC map mask register
GC_INDEX equ 3ceh ;GC index register
GC_MODE equ 5 ;GC mode register
CRTC_INDEX equ 03d4h ;CRTC index register
START_ADDRESS_HIGH equ 0ch ;CRTC start address high byte
START_ADDRESS_LOW equ 0dh ;CRTC start address low byte
CRTC_OFFSET equ 13h ;CRTC offset register
INPUT_STATUS_1 equ 03dah ;VGA status register
VSYNC_MASK equ 08h ;vertical sync bit in status register 1
DE_MASK equ 01h ;display enable bit in status register 1
AC_INDEX equ 03c0h ;AC index register
HPELPAN equ 20h OR 13h ;AC horizontal pel panning register
; (bit 7 is high to keep palette RAM
; addressing on)
SC_INDEX equ 3c4h ;SC index register
MAP_MASK equ 2 ;SC map mask register
GC_INDEX equ 3ceh ;GC index register
GC_MODE equ 5 ;GC mode register
CRTC_INDEX equ 03d4h ;CRTC index register
START_ADDRESS_HIGH equ 0ch ;CRTC start address high byte
START_ADDRESS_LOW equ 0dh ;CRTC start address low byte
CRTC_OFFSET equ 13h ;CRTC offset register
INPUT_STATUS_1 equ 03dah ;VGA status register
VSYNC_MASK equ 08h ;vertical sync bit in status register 1
DE_MASK equ 01h ;display enable bit in status register 1
AC_INDEX equ 03c0h ;AC index register
HPELPAN equ 20h OR 13h ;AC horizontal pel panning register
; (bit 7 is high to keep palette RAM
; addressing on)
dseg segment para common 'DATA'
CurrentPage db PAGE1 ;page to draw to
CurrentPage db PAGE1 ;page to draw to
CurrentPageOffset dw PAGE1_OFFSET
;
; Four plane's worth of multicolored ball image.
@ -128,15 +128,15 @@ PanningControlString dw 32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, -1, 0
else
PanningControlString dw 32, 1, 0, 184, 0, 1, 32, -1, 0, 184, 0, -1, 0
endif
PanningControl dw PanningControlString ;pointer to current location
; in panning control string
PanningRep dw 1 ;# times to pan according to current
; panning increments
PanningXInc dw 1 ;x panning factor
PanningYInc dw 0 ;y panning factor
HPan db 0 ;horizontal pel panning setting
PanningStartOffset dw 0 ;start offset adjustment to produce vertical
; panning & coarse horizontal panning
PanningControl dw PanningControlString ;pointer to current location
; in panning control string
PanningRep dw 1 ;# times to pan according to current
; panning increments
PanningXInc dw 1 ;x panning factor
PanningYInc dw 0 ;y panning factor
HPan db 0 ;horizontal pel panning setting
PanningStartOffset dw 0 ;start offset adjustment to produce vertical
; panning & coarse horizontal panning
dseg ends
;
; Macro to set indexed register P2 of chip with index register
@ -172,31 +172,31 @@ endif
; Draw border around playfield in both pages.
;
mov di,PAGE0_OFFSET
call DrawBorder ;page 0 border
call DrawBorder ;page 0 border
mov di,PAGE1_OFFSET
call DrawBorder ;page 1 border
call DrawBorder ;page 1 border
;
; Draw all four plane's worth of the ball to undisplayed VGA memory.
;
mov al,01h ;enable plane 0
mov al,01h ;enable plane 0
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane0Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,02h ;enable plane 1
mov al,02h ;enable plane 1
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane1Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,04h ;enable plane 2
mov al,04h ;enable plane 2
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane2Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,08h ;enable plane 3
mov al,08h ;enable plane 3
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane3Image
mov di,BALL_OFFSET
@ -205,8 +205,8 @@ endif
;
; Draw a blank image the size of the ball to undisplayed VGA memory.
;
mov al,0fh ;enable all memory planes, since the
SETREG SC_INDEX, MAP_MASK ; blank has to erase all planes
mov al,0fh ;enable all memory planes, since the
SETREG SC_INDEX, MAP_MASK ; blank has to erase all planes
mov di,BLANK_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
sub al,al
@ -216,13 +216,13 @@ endif
;
mov dx,GC_INDEX
mov al,GC_MODE
out dx,al ;point GC Index to GC Mode register
inc dx ;point to GC Data register
jmp $+2 ;delay to let bus settle
in al,dx ;get current state of GC Mode
and al,not 3 ;clear the write mode bits
or al,1 ;set the write mode field to 1
jmp $+2 ;delay to let bus settle
out dx,al ;point GC Index to GC Mode register
inc dx ;point to GC Data register
jmp $+2 ;delay to let bus settle
in al,dx ;get current state of GC Mode
and al,not 3 ;clear the write mode bits
or al,1 ;set the write mode field to 1
jmp $+2 ;delay to let bus settle
out dx,al
;
; Set VGA offset register in words to define logical screen width.
@ -253,12 +253,12 @@ EachBallLoop:
;
; Change the ball movement values if it's time to do so.
;
dec [BallRep+bx] ;has current repeat factor run out?
dec [BallRep+bx] ;has current repeat factor run out?
jnz MoveBall
mov si,[BallControl+bx] ;it's time to change movement values
lodsw ;get new repeat factor from
; control string
and ax,ax ;at end of control string?
mov si,[BallControl+bx] ;it's time to change movement values
lodsw ;get new repeat factor from
; control string
and ax,ax ;at end of control string?
jnz SetNewMove
mov si,[BallControlString+bx] ;reset control string
lodsw ;get new repeat factor
@ -366,18 +366,18 @@ start endp
;
DrawBall proc near
mov ax,LOGICAL_SCREEN_WIDTH
mul dx ;offset of start of top image scan line
add ax,cx ;offset of upper left of image
mul dx ;offset of start of top image scan line
add ax,cx ;offset of upper left of image
add ax,[CurrentPageOffset] ;offset of start of page
mov di,ax
mov bp,BALL_HEIGHT
push ds
push es
pop ds ;move from VGA memory to VGA memory
pop ds ;move from VGA memory to VGA memory
DrawBallLoop:
push di
mov cx,BALL_WIDTH
rep movsb ;draw a scan line of image
rep movsb ;draw a scan line of image
pop di
add di,LOGICAL_SCREEN_WIDTH ;point to next destination scan line
dec bp
@ -418,7 +418,7 @@ WaitDisplayEnable endp
; Perform horizontal/vertical panning.
;
AdjustPanning proc near
dec [PanningRep] ;time to get new panning values?
dec [PanningRep] ;time to get new panning values?
jnz DoPan
mov si,[PanningControl] ;point to current location in
; panning control string
@ -483,10 +483,10 @@ DrawBorder proc near
push di
mov cx,LOGICAL_SCREEN_HEIGHT / 16
DrawLeftBorderLoop:
mov al,0ch ;select red color for block
mov al,0ch ;select red color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
mov al,0eh ;select yellow color for block
mov al,0eh ;select yellow color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
loop DrawLeftBorderLoop
@ -498,10 +498,10 @@ DrawLeftBorderLoop:
add di,LOGICAL_SCREEN_WIDTH - 1
mov cx,LOGICAL_SCREEN_HEIGHT / 16
DrawRightBorderLoop:
mov al,0eh ;select yellow color for block
mov al,0eh ;select yellow color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
mov al,0ch ;select red color for block
mov al,0ch ;select red color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
loop DrawRightBorderLoop
@ -513,10 +513,10 @@ DrawRightBorderLoop:
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
DrawTopBorderLoop:
inc di
mov al,0eh ;select yellow color for block
mov al,0eh ;select yellow color for block
call DrawBorderBlock
inc di
mov al,0ch ;select red color for block
mov al,0ch ;select red color for block
call DrawBorderBlock
loop DrawTopBorderLoop
pop di
@ -527,10 +527,10 @@ DrawTopBorderLoop:
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
DrawBottomBorderLoop:
inc di
mov al,0ch ;select red color for block
mov al,0ch ;select red color for block
call DrawBorderBlock
inc di
mov al,0eh ;select yellow color for block
mov al,0eh ;select yellow color for block
call DrawBorderBlock
loop DrawBottomBorderLoop
ret

View file

@ -23,10 +23,10 @@ VERTICAL_BOX_WIDTH_IN_BYTES equ 10 ;width in bytes of the box used to
;
; VGA register equates.
;
GC_INDEX equ 3ceh ;GC index register
GC_ROTATE equ 3 ;GC data rotate/logical function
; register index
GC_MODE equ 5 ;GC mode register index
GC_INDEX equ 3ceh ;GC index register
GC_ROTATE equ 3 ;GC data rotate/logical function
; register index
GC_MODE equ 5 ;GC mode register index
;
dseg segment para common 'DATA'
;
@ -40,10 +40,13 @@ LABEL_STRING_LENGTH equ $-LabelString
;
FillPatternFF db 'Fill Pattern: 0FFh'
FILL_PATTERN_FF_LENGTH equ $ - FillPatternFF
FillPattern00 db 'Fill Pattern: 000h'
FILL_PATTERN_00_LENGTH equ $ - FillPattern00
FillPatternVert db 'Fill Pattern: Vertical Bar'
FILL_PATTERN_VERT_LENGTH equ $ - FillPatternVert
FILL_PATTERN_VERT_LENGTH equ $ - FillPatternVert
FillPatternHorz db 'Fill Pattern: Horizontal Bar'
FILL_PATTERN_HORZ_LENGTH equ $ - FillPatternHorz
;
@ -65,9 +68,9 @@ TEXT_UP macro TEXT_STRING, TEXT_LENGTH, ROW, COLUMN
mov ah,13h ;BIOS write string function
mov bp,offset TEXT_STRING ;ES:BP points to string
mov cx,TEXT_LENGTH
mov dx,(ROW SHL 8) OR COLUMN ;position
sub al,al ;string is chars only, cursor not moved
mov bl,7 ;text attribute is white (light gray)
mov dx,(ROW SHL 8) OR COLUMN;position
sub al,al ;string is chars only, cursor not moved
mov bl,7 ;text attribute is white (light gray)
int 10h
endm
;
@ -90,19 +93,19 @@ start proc near
; Draw background of horizontal bars.
;
mov dx,SCREEN_HEIGHT/4
;# of bars to draw (each 4 pixels high)
sub di,di ;start at offset 0 in display memory
mov ax,0ffffh ;fill pattern for light areas of bars
;# of bars to draw (each 4 pixels high)
sub di,di ;start at offset 0 in display memory
mov ax,0ffffh ;fill pattern for light areas of bars
mov bx,DEMO_AREA_WIDTH_IN_BYTES / 2 ;length of each bar
mov si,SCREEN_WIDTH_IN_BYTES - DEMO_AREA_WIDTH_IN_BYTES
mov bp,(SCREEN_WIDTH_IN_BYTES * 3) - DEMO_AREA_WIDTH_IN_BYTES
BackgroundLoop:
mov cx,bx ;length of bar
rep stosw ;draw top half of bar
add di,si ;point to start of bottom half of bar
mov cx,bx ;length of bar
rep stosw ;draw bottom half of bar
add di,bp ;point to start of top of next bar
mov cx,bx ;length of bar
rep stosw ;draw top half of bar
add di,si ;point to start of bottom half of bar
mov cx,bx ;length of bar
rep stosw ;draw bottom half of bar
add di,bp ;point to start of top of next bar
dec dx
jnz BackgroundLoop
;
@ -204,12 +207,12 @@ ColumnLoop:
;
DrawVerticalBox proc near
DRAW_BOX_QUARTER 0ffh, VERTICAL_BOX_WIDTH_IN_BYTES
;first fill pattern: solid fill
;first fill pattern: solid fill
DRAW_BOX_QUARTER 0, VERTICAL_BOX_WIDTH_IN_BYTES
;second fill pattern: empty fill
;second fill pattern: empty fill
DRAW_BOX_QUARTER 033h, VERTICAL_BOX_WIDTH_IN_BYTES
;third fill pattern: double-pixel
; wide vertical bars
;third fill pattern: double-pixel
; wide vertical bars
mov dx,DEMO_AREA_HEIGHT / 4 / 4
;fourth fill pattern: horizontal bars in
; sets of 4 scan lines

View file

@ -77,6 +77,7 @@ HorzBarLoop:
SETGC GC_SET_RESET,01h ;set/reset value is 0ffh for plane 0
; (the blue plane) and 0 for other
; planes
int 3
sub di,di
mov cx,80*480 ;# bytes per screen
mov al,0ffh ;since set/reset is enabled for all

View file

@ -19,7 +19,7 @@ I assume something similar was done on the CD-ROM that accompanied the Black Boo
book or its CD-ROM, I'm extracting the source code directly from the Markdown text, and then "tabifying" it with 8-column
tab stops.
Development of PCjs VGA support has just begun (June 2015), so don't expect *anything* here to to run properly yet.
Development of PCjs VGA support has just begun (June 2015), so don't expect everything here to to run properly yet.
---
@ -50,7 +50,7 @@ Since the contents of this particular directory will probably be in flux for a w
Once things settle down, I'll generate a JSON-encoded disk image containing a snapshot of this directory, using the
PCjs [DiskDump](/modules/diskdump/) module:
diskdump --dir=. --format=img --output=TESTVGA.img
diskdump --dir=. --format=img --output=TESTVGA.img --overwrite
One advantage of using [DiskDump](/modules/diskdump/) is that it automatically converts linefeeds in known text files
(including ASM files) into DOS-compatible CR/LF sequences.