• Please review our updated Terms and Rules here

Some PCjr programming fun

The 160x100 mode I discovered (NOT the same as the CGA "lowres" textmode hack) is truly PCjr-specific. If you run both programs on a Tandy 1000, they run fine, but every other scanline is black. Also, if you run on a Tandy 1000, the raster bars effect is missing.

Setting the mode is as follows:

Code:
{
If you set the CRT and CPU page registers
with the WRONG video addressing mode bits 7-6, you can get double or
mismatched pixels.  PCjr tech ref states "These bits control whether
the row scan addresses are used as part of the memory address."
}

  mov     ax,0008h        {init 160x200x16 mode}
  int     10h
  mov     ax,0580h        {grab CRT/CPU page registers}
  int     10h
  mov     jrPageRegs,bx   {hold onto them for later}
  mov     vidAddressMode,$00 {lower! graphics}

  {We need to set CRT and CPU page registers with "wrong" video addressing
  bits to get the double-pixels to show up}
  mov     al,vidAddressMode       {load addressing mode}
  mov     cl,2
  ror     al,cl                   {addressing mode into bits 7-6}
  inc     cx
  shl     bl,cl                   {cpu page into bits 5-3}
  or      al,bl                   {vv888???}
  or      al,bh                   {vv888ccc}
  mov     dx,pageRegsPort
  out     dx,al                   {set CRT and CPU page registers}

These are part of a library that also handles pageflipping in the 160x??? modes, sets colors on a PCjr, drives the sound, etc. I've attached both support libraries to this post. The PCjr library states "also tandy 1000" but that is a lie.
 

Attachments

  • pcjrsupp.txt
    13.7 KB · Views: 1
  • m6845ctl.txt
    15.2 KB · Views: 1
...and now we know how it works. :) Thanks for the details - it never ceases to surprise me how these old pieces of hardware react when told to do things they're technically not supposed to do.
 
I, admittedly, know nothing about graphics programming, but I noticed that the Tandy TL technical reference mentions a "double scan" mode control register bit (on page 322 of the PDF). Could this be used to duplicate the line-doubling PCjr effect on a Tandy system?
 
I'll answer with a counter-example: I can read the video retrace status bit, but that doesn't imply I should be able to force retrace arbitrarily by attempting to set that bit.
 
The graphics are impressive, but I have to say the music sounds rather shrill. :rocknroll: It would benefit from a bass line -- although I'm well aware that the PCjr/Tandy is notably weak in this department, not even being able to reach down all the way through the "octave 0" that the normal PC speaker can play.

Still, I've been able to produce some interesting low tones on the Tandy by mixing together the lowest octave with the noise generator channel:

 
Well, there's no real reason you couldn't use the PC speaker itself as the bassline, or even as a sub-oscillator to thicken up a bassline on one of the PSG channels.
 
Well, there's no real reason you couldn't use the PC speaker itself as the bassline, or even as a sub-oscillator to thicken up a bassline on one of the PSG channels.

That's what I've always wondered... is it possible to do PC speaker audio and PCjr/Tandy 3-voice audio simultaneously?
 
That's what I've always wondered... is it possible to do PC speaker audio and PCjr/Tandy 3-voice audio simultaneously?

Yea, verily. A few games do exactly this.

Since we're going all out, why not tailor something specifically for the PSSJ though, which can produce frequencies an octave lower than the standard SN76496 (down to 54.62Hz)? Of course, you'd also want to use one of the non-square waveforms available to the additional PSG channel at that point, to make it extra special and all. :)

Methinks the world needs a demo that takes full advantage of the Tandy PSSJ and 640x200x16 graphics mode...
 
Should be, they're completely independent hardware. Of course, the PC speaker doesn't have volume adjust the way the PSG channels do, but you can still do a lot with it.

Since we're going all out, why not tailor something specifically for the PSSJ though, which can produce frequencies an octave lower than the standard SN76496 (down to 54.62Hz)? Of course, you'd also want to use one of the non-square waveforms available to the additional PSG channel at that point, to make it extra special and all. :)

Methinks the world needs a demo that takes full advantage of the Tandy PSSJ and 640x200x16 graphics mode...
Hmm. I wasn't aware that the Tandys used an expanded version relative to the standard PSG...that would be pretty sweet.
 
Uhm... couple questions.

Code:
  mov     al,vidAddressMode       {load addressing mode}
  mov     cl,2                    
  ror     al,cl                   { 16 clocks , 2 fetch}
  inc     cx
  shl     bl,cl                   {20 clocks, 2 fetch}
  or      al,bl                   {vv888???}
  or      al,bh                   {vv888ccc}

You KNOW vidAddressMode is zero at that point, so why bother putting it in AL or shifting it, it's STILL going to be zero. Likewise it would probably be faster to unroll the shift instead of using CL.

Code:
  shl     bl,1                      { usually faster unrolled }
  shl     bl,1
  shl     bl,1
  mov     al,bh
  or      al,bl                   {vv888ccc}

Should be functionally identical. Just saying...

Also, when you say it's 'linear' is it truly linear, or is it still interlaced CGA style by scanline? (Didn't dig that far into your code yet)
 
You're looking at snippets of code from a library, and the library handles hardware pageflipping for any graphics mode. That's why it performs redundant operations on a 0 value. Not all values fed to that routine will be 0.

The mode is a true linear organization.
 
Seemed like you 'unrolled' them as standalone in the library, which is why I pointed it out... jrInit160x100 seems to have it's own copy and always be zero. jrInit160x200 doesn't even do that part.

Looking at jrPixelAddr160x100, I know the comment for jrSetPix160x100 says it's not optimal yet, so I've been playing with it.

If you did a load into ES:DI first, then added to DI, you could do your shifts in just one direction.
Code:
	les  di,curpageaddr
	xchg ah,al
	shr  ax,1
	shr  ax,1
	add  di,ax
	shr  ax,1
	shr  ax,1
	add  di,ax

The math for turning the bottom bit of CL into 4 or 0 also seems slow -- strange as it sounds, a conditional based on the carry flag after the shift of BX would probably be faster.

Code:
	shr  bx,1
	jc   @bitShift
	
	xor  cl,cl
	mov  ah,$F0
	jmp  @final

@bitShift:
	mov  cl,4
	mov  ah,$0F
	
@final:
	add  bx,di

Which unfolded into the setpixel routine could be even more optimal.

Code:
Procedure jrSetPix160x100(x,y:word; color:byte); assembler;
asm
	les   di,curpageaddr
  
	mov   ax,y
	xchg  al,ah
	shr   ax,1
	shr   ax,1  
	add   di,ax
	shr   ax,1
	shr   ax,1
	add   di,ax
  
	mov   al,color
	mov   bx,x
	shr   bx,1
	jc    @shifted
	
	mov   ah,$F0
	jmp   @blit
	
@shifted:
	mov   ah,$0F
	shl   al,1
	shl   al,1
	shl   al,1
	shl   al,1
	
@blit:
	add   di,bx
	and   es:[di],ah
	or    es:[di],al

end;

Which it feels unnatural and just plain wrong for a conditional jump to be faster, but it happens.

Just some thoughts -- As it is I've been playing with a tandy/jr only port of paku paku for the 160x200 mode, since that resolution worked out nice for the C64 version... though I'm wondering if there's enough CPU to make a 320x200 version. (I did have a scanline doubling 160x200 version for a bit so...)
 
Still, I've been able to produce some interesting low tones on the Tandy by mixing together the lowest octave with the noise generator channel:

There is a periodic noise function that you can gang to channel 3 to produce "noise" at lower octaves. However, you lose channel 3 in doing so, leaving you with only 2 tone channels. So that's why you don't hear it being done very often.

That's what I've always wondered... is it possible to do PC speaker audio and PCjr/Tandy 3-voice audio simultaneously?

On Tandy, yes. On PCjr, no, due to the way the audio multiplexor was implemented.
 
Back
Top