Correct VDC Programming from BASIC

Started by BigDumbDinosaur, January 21, 2008, 09:18 AM

Previous topic - Next topic

0 Members and 4 Guests are viewing this topic.

BigDumbDinosaur

Elsewhere on this site, I've seen various code examples for programming the VDC from BASIC using POKEs and PEEKs.  This method of programming the VDC is incorrect and may cause all sorts of strange and hard-to-fix errors.  Below is an edited statement that was originally found in the VDC technical documentation provided to early 128 developers:

Commodore's specifications for this chip state that when accessing the VDC, you should avoid machine language instructions that use the indirect addressing mode.  That is, you should avoid using instructions like LDA ($CC),Y to read this register because the VDC apparently responds improperly to such instructions.  This imposes no particular hardship on machine language programmers, but has highly unfortunate consequences for BASIC programmers.  The 128's PEEK, POKE, and WAIT instructions are implemented using the Kernal INDFET, INDSTA, and INDCMP routines, all of which use indirect-Y addressing to read or store values.  As a result, you should not use PEEK, POKE, or WAIT statements to read or change the contents of the VDC registers.


The correct way to control the VDC from BASIC is by using two screen editor ROM primitives located at $CDCC and $CDDA.  The former, officially referred to as WRITEREG, writes to a selected register in the VDC.  The other location, READREG, reads from a selected VDC register.

To use WRITEREG from BASIC, you would code:

BANK 15:SYS("CDCC"),D,R

where D is the byte to be written and R is the desired register number.

To use READREG from BASIC, you would code:

BANK 15:SYS("CDDA"),,R:RREG D

where R is the desired register number.  The value in the register will be returned in D.

This quirk in the C-128's hardware was apparently discovered during the prototyping phase, but was never fixed.  The story I was told by Fred Bowen was that everyone was rushing to complete a working machine in time for demonstration at the January 1985 Consumer Electronics Show.  When this little gotcha was discovered, there wasn't enough time to do a new mask for the 8563, which had experienced all sorts of teething problems from the get go.  So the problem has persisted to this day.

Please!  Let's get it right for the noobies who are learning how to make their C-128s do what they want.  Perpetuating the PEEK/POKE method simply complicates things for them.
x86?  We ain't got no x86.  We don't need no stinking x86!

StyleCHM

Interesting, I had read about the indirect addressing mode but didnt realise peek/poke etc used it.

I cant get my head around the logic of it though. Itd be nice to understand why. I cant see why indirect addressing is a special case.

Just as an aside, I recently did a 64k upgrade and ran the old basic test - first time I ran it, it failed. I was just about to panic and reach for the soldering iron again when I ran it again and it worked. Possibly Id made a typo, but I guess there's also a chance that the write failed.


nikoniko

#2
Quote from: BigDumbDinosaur on January 21, 2008, 09:18 AMThe 128's PEEK, POKE, and WAIT instructions are implemented using the Kernal INDFET, INDSTA, and INDCMP routines, all of which use indirect-Y addressing to read or store values.  As a result, you should not use PEEK, POKE, or WAIT statements to read or change the contents of the VDC registers.

Well then, we'll just switch to 64 mode and do our PEEKs and POKEs from there. :P

Seriously, though, I'm all for Sticky-ing this thread. Lance?

EDIT: Ah, found my Sticky button.

BigDumbDinosaur

Quote from: Michael Hart on January 21, 2008, 10:37 AM
Quote from: BigDumbDinosaur on January 21, 2008, 09:18 AMThe 128's PEEK, POKE, and WAIT instructions are implemented using the Kernal INDFET, INDSTA, and INDCMP routines, all of which use indirect-Y addressing to read or store values.  As a result, you should not use PEEK, POKE, or WAIT statements to read or change the contents of the VDC registers.

Well then, we'll just switch to 64 mode and do our PEEKs and POKEs from there. :P

You'll experience the same problem, since PEEK and POKE in BASIC 2.0 is implemented with indirect addressing as well.  A tiny M/L priimitive is all that's needed to drive the VDC on the 64 side:


         stx $d600           ;set register to be accessed
wait     bit $d600           ;wait until VDC is ready
         bpl wait
         lda $d601           ;read register
         ---or---
         sta $d601           ;write register
         rts


That's all there is to it and it works like a charm every time.  You can stash that little subroutine almost anywhere (except in the $D000 range, of course).  Do it right and it'll work right.  Do it with PEEK and POKE and you'll go nuts with random errors.
x86?  We ain't got no x86.  We don't need no stinking x86!

StyleCHM

Just to answer my own question, I googled a bit and it seems that STA($ZP),Y will fail sometimes because the cycle before it does the write, it does a read...... Depending on the timing (given that the CPU clock and VDC clock are asynchronous), Im guessing that it would mean that the read and write can sometimes occur in the same VDC clock (maybe), which would cause an issue.

Something like that anyway.


BigDumbDinosaur

Quote from: StyleCHM on January 21, 2008, 11:31 AM
Just to answer my own question, I googled a bit and it seems that STA($ZP),Y will fail sometimes because the cycle before it does the write, it does a read...... Depending on the timing (given that the CPU clock and VDC clock are asynchronous), Im guessing that it would mean that the read and write can sometimes occur in the same VDC clock (maybe), which would cause an issue.

Something like that anyway.


I've never found or heard a satisfactory explanation for this problem, except that the evanesence of the VDC's registers may be to blame.  I don't know that it is a clocking issue, since access to anything in the I/O block occurs on the 1 MHz clock, regardless of processor clock speed.  However, the VDC does have its own video dot clock and therefore there may be internal issues involving timing between the I/O clock and the dot clock.

I got my first C-128 in September 1985 and by good fortune, was able to get my hands on technical information that wasn't generally available.  I recall playing around with the POKE and PEEK techniques and simply not being able to get consistent results.  Then I started digging into the docs and discovered the caveat about indirect loads and stores to the VDC.  That prompted me to dig into the screen editor ROM, since I surmised that there must be a bullet-proof way of driving the VDC—the ROM routines seemed to work very well.

The first thing I wrote for the 128 was a clock-calendar program that would drive a date and time display on both screens from interrupts.  It was an interesting exercise getting the 80 column side to work right, due to the need to avoid tripping over the screen editor ROM when it was updating the VDC.  It took stack sniffing to watch for when something else was accessing the VDC—my program would skip the 80 column update if it saw anything on the stack that indicated the VDC was being driven by ROM.

I later developed a trickier version of the clock-calendar program that created a status line at the bottom of the screen on an extra row created by twiddling with the VDC.  Again, stack sniffing kept my code from interfering with the editor ROM.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

#6
Quote from: BigDumbDinosaur on January 21, 2008, 11:02 AM
Quote from: Michael Hart on January 21, 2008, 10:37 AM
Well then, we'll just switch to 64 mode and do our PEEKs and POKEs from there. :P

You'll experience the same problem, since PEEK and POKE in BASIC 2.0 is implemented with indirect addressing as well.  A tiny M/L priimitive is all that's needed to drive the VDC on the 64 side:

Sorry, I should've made it more clear I was joking about Commodore naming INDFET et al here, as if the indirect addressing is 128 mode specific, when in fact, as you point out, PEEK and POKE use indirect addressing in 64 mode as well. But nonetheless your ML is useful to have here, so thank you for adding it to the thread.


smf

Quote from: StyleCHM on January 21, 2008, 10:25 AM
Interesting, I had read about the indirect addressing mode but didnt realise peek/poke etc used it.

I cant get my head around the logic of it though. Itd be nice to understand why. I cant see why indirect addressing is a special case.

I don't wonder why it sometimes fails, I wonder how it ever works.

http://home.datacomm.ch/fmeyer/c64/c128_story.html

BigDumbDinosaur

Since I apparently have opened up a can of worms with this topic, I thought that maybe I should post a response that I placed elsewhere to the subject of figuring out how much video RAM is hooked up to the VDC.

Quote from: xlar54 on January 21, 2008, 03:16 PM
Since we're in the thread, can you help with a quick ML or BASIC routine one might call to determine 16k or 64k by using the correct access method?

Your wish is (somewhat) my command.

Rotting somewhere in this vast depository of refuse I call my shop are some assembly language listings of code I hammered into the 128 back in the day.  I'm reasonably certain that an M/L routine I wrote for positively detecting the amount of video RAM hooked up to the VDC is in that compost pile.  Once I find it, I'll get it into a format that can be somehow made available to anyone who has a MOS Technology-compliant assembler.

My recollection is that late in 1987, I was on the horn with Fred Bowen on another matter and the subject of determining how much video RAM was installed came up.  Fred described to over the phone how to conduct such a test—telling me which video RAM locations to twiddle, etc.  I jotted some notes and was going to start programming when Fred said he could FAX me a copy of a BASIC program he had written to do the testing, but was not always working as it should.  Turns out the trouble was being caused by some PEEKing and POKEing he was doing to the VDC, which as everyone should know, doesn't work all the time.

Since I've never really liked BASIC, I said, "Screw that!" and using Fred's program as a guide (why reinvent the wheel) cobbled together a short M/L routine to do the testing.  It worked fine on both of the flat 128s I had at the time, as well as my then newly-acquired 128D.

Since I'll be out of commission starting on Friday, I may not be able to get the source code up here for a while.  First I have to find it, though.  Otherwise, I will rewrite it from scratch, since for reasons that totally baffle me, I think I recall exactly how to do it.  If I do rewrite it, I'll need some volunteers to test the result, since I don't have any real 128 hardware anymore and, unlike the current resident of the Vatican, I don't claim to be infallible.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

#9
BDD, for historical interest, this is what Fred was posting to Usenet years ago and may be similar or the same as what he sent you. Odd thing about it is that he uses calls to the screen editor most of the time, yet relies on PEEKs and POKEs for dealing with register 28. That inspired me to run a little "stress test" on my flat 128, where over 10000 operations each I found that reading or writing register 28 the wrong way usually succeeds, 18 and 19 often work, and 31 is completely hit or miss. PEEKing and POKEing the VDC could be fun stuff if one were a gambling man. :)

Original:

  1 rem fred's nifty program to determine size of 8563 dram
  5 w=dec("cdcc"):r=dec("cdda")
  10 bank15: ad=dec("d600"): da=ad+1 :rem setup ml
  20 pokead,28: s=peek(da): pokeda,63 :rem select 64k
  30 i=16896: sysw,i/256,18:sysw,iand255,19:sysw,85,31 :rem write $55
  40 i=16896: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc1 :rem read here
  50 i=17152: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc2 :rem and here
  60 i=16896: sysw,i/256,18:sysw,iand255,19:sysw,170,31 :rem write $aa
  70 i=16896: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc3 :rem read here
  80 i=17152: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc4 :rem and here
  90 pokead,28: pokeda,s:sysdec("ff62") :rem restore 16/64k
  95 print chr$(14)chr$(147)
  100 if c1=c2 and c3=c4 then print "16K": else print"64K"  :rem did it echo?
  110 end


Corrected to remove PEEKs and POKEs:

  1 rem fred's nifty program to determine size of 8563 dram
  5 w=dec("cdcc"):r=dec("cdda")
  10 bank15: rem setup ml
  20 sys r,,28: rreg s: sys w,63,28: rem select 64k
  30 i=16896: sysw,i/256,18:sysw,iand255,19:sysw,85,31 :rem write $55
  40 i=16896: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc1 :rem read here
  50 i=17152: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc2 :rem and here
  60 i=16896: sysw,i/256,18:sysw,iand255,19:sysw,170,31 :rem write $aa
  70 i=16896: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc3 :rem read here
  80 i=17152: sysw,i/256,18:sysw,iand255,19:sysr,,31:rregc4 :rem and here
  90 sys w,s,28:sysdec("ff62") :rem restore 16/64k
  95 print chr$(14)chr$(147)
  100 if c1=c2 and c3=c4 then print "16K": else print"64K"  :rem did it echo?
  110 end


Pretty straightforward to convert to M/L as it mainly works out to just a bunch of LDA #value, LDX #register, JSR writereg... LDX #register, JSR readreg, STA somewhere.

BigDumbDinosaur

#10
I found the much-wrinkled and yellowed, but otherwise readable, M/L source code listing for checking the amount of video RAM in a 128, but did not find the copy of the BASIC program that I got from Fred Bowen way back when.  It appears, however, that what he posted in USENET is the same as what he had FAXed to me in 1987.

What follows is a cleaned-up version of the original source code.  I've test-assembled it with my UNIX 6502 assembler (100 percent MOS Technology compliant, except it supports longer labels and symbols) and it should be good to try out.  I haven't tested it on a real 128, since I don't have access to one.  However, I see no reason why it shouldn't work.  It assembles into the 128's cassette buffer at $0B00, but may be relocated as needed, as long as it is visible in RAM0 below $C000.


;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;*                                                                             *
;*                Test & Report Available Video RAM in C-128                   *
;*                                                                             *
;* This program positively determines the amount of video RAM connected to the *
;* 8563/8568 video display controller in the C-128.   It is a machine language *
;* implementation of a BASIC 7.0 program written by CBM kernal developer  Fred *
;* Bowen in late 1987.                                                         *
;*                                                                             *
;* Copyright (c)1987 by BCS Technology Limited.   Redistribution is  permitted *
;* subject to retention of copyright notice & attribution.  Any redistribution *
;* must be at no charge to the end user.                                       *
;*                                                                             *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;*                                                                             *
;* BASIC syntax for running this test:                                         *
;*                                                                             *
;*      BANK 15 : SYS DEC("0B00") : RREG VS                                    *
;*      PRINT "This 128 has";VS;"K video RAM."                                 *
;*                                                                             *
;*      VS will equal 16 for a C-128 with 16K of VRAM or 64 for a machine with *
;*      with 64K of VRAM.                                                      *
;*                                                                             *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;* * * * * * * * * * *
;*                   *
;* REVISION  HISTORY *                                         
;*                   *
;* * * * * * * * * * *
;
;Ver    Rev Date    Revision
;================================================================================
;1.0   12/09/1987   Original version.
;================================================================================
;
;
;* * * * * * * * * * * * *
;*                       *
;* <<< PROGRAM NOTES >>> *
;*                       *
;* * * * * * * * * * * * *
;
;Comment abbreviations are as follows:
;
;    .A MPU accumulator
;    .X MPU X index register
;    .Y MPU Y index register
;   CBM Commodore Business Machines
;  DRAM dynamic random access memory
;  KRAM character shape RAM
;   LSB least significant byte
;   MPU microprocessor
;   MSB most significant byte
;   VDC 8563/8568 video display controller
;  VRAM VDC video RAM (16K or 64K)
;
;================================================================================
;
;main program declarations
;
_origin_ =$0b00                ;cassette buffer, relocate if desired
;
dlchr    =$c027                ;initialize VDC character RAM
mmucr    =$ff00                ;MMU config register
mmumask  =%00001110            ;memory map mask
ramsmall =16                   ;returned for 16K VRAM
ramlarge =64                   ;returned for 64K VRAM
read80   =$cdd8                ;read from VRAM primitive
readreg  =$cdda                ;read from VDC register primitive
testadra =$4200                ;1st VRAM test address
testadrb =$4300                ;2nd VRAM test address
testpata =%01010101            ;test bit pattern #1
testpatb =%10101010            ;test bit pattern #2
testvrt  =%00110000            ;DRAM type register setup value
write80  =$cdca                ;write to VRAM primitive
writereg =$cdcc                ;write to VDC register primitive
;
;================================================================================
;
;8563/8568 VDC internal registers
;
vramhi   =18                   ;VRAM address (MSB), autoincrementing
vramlo   =19                   ;VRAM address (LSB), autoincrementing
kramad   =28                   ;KRAM starting address & VRAM type...
;
; Bit  Meaning
; ----------------------------------------
; 0-3  unused (mask off)
; 4   VRAM chip type: 0 = 4416 (flat 128)
;                      1 = 4464 (128DCR)
; 5-7  start of KRAM
; ----------------------------------------
;
vramrw   =31                   ;VRAM read/write access
;
;================================================================================
;
;temporary storage -- can be moved from ZP if necessary
;
kramregv  =$fa                 ;place to stash current KRAM value
rbitpata  =$fb                 ;returned bit pattern from 1st test
rbitpatb  =$fc                 ;returned bit pattern from 2nd test
rbitpatc  =$fd                 ;returned bit pattern from 3rd test
rbitpatd  =$fe                 ;returned bit pattern from 4th test
;
;================================================================================
;
         *=_origin_
;
chkvdc   lda #mmumask
         sta mmucr             ;select RAM0, I/O block & high ROM
;
; prepare VDC for testing...
;
         ldx #kramad           ;KRAM & VRAM type reg
         jsr readreg           ;get it...
         and #%11110000        ;mask dead bits &...
         sta kramregv          ;stash it
         lda #testvrt
         jsr writereg          ;tell VDC it has 64K VRAM
;
; The basis on which this test works is relatively simple.  We've told
; the VDC that it has 4464 DRAM, which means it thinks that it has 64K
; of VRAM.  If it really does, the column & row address enables associated
; with the selected test addresses will see real RAM.  If only 16K of VRAM
; is present, the col/row enables will goof up & select the same hardware
; address despite the two disparate test addresses.
;
; So, what we're doing is writing some test patterns into RAM locations
; that could only exist if 64K of VRAM really was present.  We then read
; the test VRAM locations & check for the presence of the test pattern.
; If the test pattern written into the lower of the test locations shows
; up in the higher location, then the machine has 16K of VRAM.
;
; To verify the results, 2 test patterns are used, with opposite bit
; patterns (01010101 & 10101010).  This is done just in case one of the
; test locations in VRAM just happens to have one or the other test
; patterns.
;
; Note that checking the VRAM type in VDC register 28 is not reliable,
; since a program bug could change that value.
;
         lda #testpata         ;1st test pattern
         ldx #<testadra        ;1st VRAM test address LSB &...
         ldy #>testadra        ;MSB
         jsr putram            ;write test pattern
         ldx #<testadra        ;1st VRAM test address LSB &...
         ldy #>testadra        ;MSB
         jsr getram            ;read back test pattern &...
         sta rbitpata          ;store it for later
         ldx #<testadrb        ;2nd VRAM test address LSB &...
         ldy #>testadrb        ;MSB
         jsr getram            ;read &...
         sta rbitpatb          ;store it as well
;
; 1st test completed & results saved
;
         lda #testpatb         ;2nd test pattern
         ldx #<testadra        ;1st VRAM test address LSB &...
         ldy #>testadra        ;MSB
         jsr putram            ;write test pattern
         ldx #<testadra        ;1st VRAM test address LSB &...
         ldy #>testadra        ;MSB
         jsr getram            ;read back test pattern &...
         sta rbitpatc          ;store it for later
         ldx #<testadrb        ;2nd VRAM test address LSB &...
         ldy #>testadrb        ;MSB
         jsr getram            ;read &...
         sta rbitpatd          ;store it as well
;
; 2nd test completed & results saved
;
         lda kramregv          ;old KRAM register value
         ldx #kramad           ;KRAM & VRAM type reg
         jsr writereg          ;restore to original config
         jsr dlchr             ;restore character patterns in VRAM
;
; here we compare the returned test patterns
;
         lda rbitpata          ;1st low address returned test value
         cmp rbitpatb          ;1st high address returned test value
         beq chkvdc02          ;same, possibly 16K VRAM
;
chkvdc01 lda #ramlarge         ;indicate 64K VRAM
         rts
;
chkvdc02 lda rbitpatc          ;low address returned test value
         cmp rbitpatd          ;high address returned test value
         bne chkvdc01          ;not same, VDC definitely has 64K VRAM
;
         lda #ramsmall         ;indicate 16K VRAM
         rts
;
;================================================================================
;
;read from VRAM
;
; .X = VRAM address LSB
; .Y = VRAM address MSB
; ---------------------
; .A = returned byte
;
; registers not preserved
;
getram   jsr setadr            ;set VRAM address &...
         jmp read80            ;read from VRAM
;
;================================================================================
;
;write to VRAM
;
; .A = byte to write
; .X = VRAM address LSB
; .Y = VRAM address MSB
;
; registers not preserved
;
putram   jsr setadr            ;set VRAM address &...
         jmp write80           ;write to VRAM
;
;================================================================================
;
;set up VRAM address
;
; .X = VRAM address LSB
; .Y = VRAM address MSB
;
; registers preserved
;
setadr   pha                   ;preserve registers
         txa
         pha
         tya                   ;VRAM address MSB
         ldx #vramhi           ;select VRAM address register MSB
         jsr writereg          ;set address MSB
         pla                   ;VRAM address LSB
         ldx #vramlo           ;select VRAM address register LSB
         jsr writereg          ;set address LSB
         tax                   ;restore
         pla                   ;likewise
         rts
;
;================================================================================


The above should assemble okay in any assembler that follows the MOS Technology 6502 recommended source syntax.  Be warned that many of the current Windows-based emulators and assemblers are not 100 percent correct in that regard.  You may have to tinker with number radices and/or language syntax (e.g. ROR A vs. ROR for accumulator rotation).  Also, your assembler might choke on eight-character labels and symbol names.

Please advise me if you try it out as to the results.  Incidentally, testing this program in VICE or another 128 emulator will be a waste of time.  At best, all you will know for sure is that the program doesn't do anything that is terminally stupid.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

Thank you for posting your code. I've no doubt it will work just fine on a real machine, and I'm just as certain it will fail on VICE. VICE doesn't implement its VDC addressing correctly, so 16K & 64K will both be identified as 64K with this sort of test. Most programs aren't adversely affected, however, since VICE doesn't care one lick if you treat a 16K machine as a 64K one. Once that bit in register 28 is set, it will happily act like a 64K machine even if the emulator setting is otherwise. Perhaps the only code ever bitten by this is a weird little infinite scrolling routine I wrote that relies on correct behavior.

The VICE team was made aware of the issue a couple months ago and received a patch for it, so I trust (hope?) things will be fixed in a future version.

BigDumbDinosaur

#12
As a reference to my previously posted source code for checking video RAM, here is the assembly listing output from my UNIX 6502 assembler.  I couldn't include it in the other post because of a character limit per post.


0001    ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0002    ;*                                                                             *
0003    ;*                Test & Report Available Video RAM in C-128                   *
0004    ;*                                                                             *
0005    ;* This program positively determines the amount of video RAM connected to the *
0006    ;* 8563/8568 video display controller in the C-128.   It is a machine language *
0007    ;* implementation of a BASIC 7.0 program written by CBM kernal developer  Fred *
0008    ;* Bowen in late 1987.                                                         *
0009    ;*                                                                             *
0010    ;* Copyright (c)1987 by BCS Technology Limited.   Redistribution is  permitted *
0011    ;* subject to retention of copyright notice & attribution.  Any redistribution *
0012    ;* must be at no charge to the end user.                                       *
0013    ;*                                                                             *
0014    ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0015    ;
0016    ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0017    ;*                                                                             *
0018    ;* BASIC syntax for running this test:                                         *
0019    ;*                                                                             *
0020    ;*      BANK 15 : SYS DEC("0B00") : RREG VS                                    *
0021    ;*      PRINT "This 128 has";VS;"K video RAM."                                 *
0022    ;*                                                                             *
0023    ;*      VS will equal 16 for a C-128 with 16K of VRAM or 64 for a machine with *
0024    ;*      with 64K of VRAM.                                                      *
0025    ;*                                                                             *
0026    ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0027    ;
0028    ;* * * * * * * * * * *
0029    ;*                   *
0030    ;* REVISION  HISTORY *                                         
0031    ;*                   *
0032    ;* * * * * * * * * * *
0033    ;
0034    ;Ver    Rev Date    Revision
0035    ;================================================================================
0036    ;1.0   12/09/1987   Original version.
0037    ;================================================================================
0038    ;
0039    ;
0040    ;* * * * * * * * * * * * *
0041    ;*                       *
0042    ;* <<< PROGRAM NOTES >>> *
0043    ;*                       *
0044    ;* * * * * * * * * * * * *
0045    ;
0046    ;Comment abbreviations are as follows:
0047    ;
0048    ;    .A MPU accumulator
0049    ;    .X MPU X index register
0050    ;    .Y MPU Y index register
0051    ;   CBM Commodore Business Machines
0052    ;  DRAM dynamic random access memory
0053    ;  KRAM character shape RAM
0054    ;   LSB least significant byte
0055    ;   MPU microprocessor
0056    ;   MSB most significant byte
0057    ;   VDC 8563/8568 video display controller
0058    ;  VRAM VDC video RAM (16K or 64K)
0059    ;
0060    ;================================================================================
0061    ;
0062    ;main program declarations
0063    ;
0064      0B00             _origin_ =$0b00                ;cassette buffer, relocate if desired
0065    ;
0066      C027             dlchr    =$c027                ;initialize VDC character RAM
0067      FF00             mmucr    =$ff00                ;MMU config register
0068      000E             mmumask  =%00001110            ;memory map mask
0069      0010             ramsmall =16                   ;returned for 16K VRAM
0070      0040             ramlarge =64                   ;returned for 64K VRAM
0071      CDD8             read80   =$cdd8                ;read from VRAM primitive
0072      CDDA             readreg  =$cdda                ;read from VDC register primitive
0073      4200             testadra =$4200                ;1st VRAM test address
0074      4300             testadrb =$4300                ;2nd VRAM test address
0075      0055             testpata =%01010101            ;test bit pattern #1
0076      00AA             testpatb =%10101010            ;test bit pattern #2
0077      0030             testvrt  =%00110000            ;DRAM type register setup value
0078      CDCA             write80  =$cdca                ;write to VRAM primitive
0079      CDCC             writereg =$cdcc                ;write to VDC register primitive
0080    ;
0081    ;================================================================================
0082    ;
0083    ;8563/8568 VDC internal registers
0084    ;
0085      0012             vramhi   =18                   ;VRAM address (MSB), autoincrementing
0086      0013             vramlo   =19                   ;VRAM address (LSB), autoincrementing
0087      001C             kramad   =28                   ;KRAM starting address & VRAM type...
0088    ;
0089    ; Bit  Meaning
0090    ; ----------------------------------------
0091    ; 0-3  unused (mask off)
0092    ; 4   VRAM chip type: 0 = 4416 (flat 128)
0093    ;                      1 = 4464 (128DCR)
0094    ; 5-7  start of KRAM
0095    ; ----------------------------------------
0096    ;
0097      001F             vramrw   =31                   ;VRAM read/write access
0098    ;
0099    ;================================================================================
0100    ;
0101    ;temporary storage -- can be moved from ZP if necessary
0102    ;
0103      00FA             kramregv  =$fa                 ;place to stash current KRAM value
0104      00FB             rbitpata  =$fb                 ;returned bit pattern from 1st test
0105      00FC             rbitpatb  =$fc                 ;returned bit pattern from 2nd test
0106      00FD             rbitpatc  =$fd                 ;returned bit pattern from 3rd test
0107      00FE             rbitpatd  =$fe                 ;returned bit pattern from 4th test
0108    ;
0109    ;================================================================================
0110    ;
0111    0B00                        *=_origin_
0112    ;
0113    0B00  A9 0E        chkvdc   lda #mmumask
0114    0B02  8D 00 FF              sta mmucr             ;select RAM0, I/O block & high ROM
0115    ;
0116    ; prepare VDC for testing...
0117    ;
0118    0B05  A2 1C                 ldx #kramad           ;KRAM & VRAM type reg
0119    0B07  20 DA CD              jsr readreg           ;get it...
0120    0B0A  29 F0                 and #%11110000        ;mask dead bits &...
0121    0B0C  85 FA                 sta kramregv          ;stash it
0122    0B0E  A9 30                 lda #testvrt
0123    0B10  20 CC CD              jsr writereg          ;tell VDC it has 64K VRAM
0124    ;
0125    ; The basis on which this test works is relatively simple.  We've told
0126    ; the VDC that it has 4464 DRAM, which means it thinks that it has 64K
0127    ; of VRAM.  If it really does, the column & row address enables associated
0128    ; with the selected test addresses will see real RAM.  If only 16K of VRAM
0129    ; is present, the col/row enables will goof up & select the same hardware
0130    ; address despite the two disparate test addresses.
0131    ;
0132    ; So, what we're doing is writing some test patterns into RAM locations
0133    ; that could only exist if 64K of VRAM really was present.  We then read
0134    ; the test VRAM locations & check for the presence of the test pattern.
0135    ; If the test pattern written into the lower of the test locations shows
0136    ; up in the higher location, then the machine has 16K of VRAM.
0137    ;
0138    ; To verify the results, 2 test patterns are used, with opposite bit
0139    ; patterns (01010101 & 10101010).  This is done just in case one of the
0140    ; test locations in VRAM just happens to have one or the other test
0141    ; patterns.
0142    ;
0143    ; Note that checking the VRAM type in VDC register 28 is not reliable,
0144    ; since a program bug could change that value.
0145    ;
0146    0B13  A9 55                 lda #testpata         ;1st test pattern
0147    0B15  A2 00                 ldx #<testadra        ;1st VRAM test address LSB &...
0148    0B17  A0 42                 ldy #>testadra        ;MSB
0149    0B19  20 6B 0B              jsr putram            ;write test pattern
0150    0B1C  A2 00                 ldx #<testadra        ;1st VRAM test address LSB &...
0151    0B1E  A0 42                 ldy #>testadra        ;MSB
0152    0B20  20 65 0B              jsr getram            ;read back test pattern &...
0153    0B23  85 FB                 sta rbitpata          ;store it for later
0154    0B25  A2 00                 ldx #<testadrb        ;2nd VRAM test address LSB &...
0155    0B27  A0 43                 ldy #>testadrb        ;MSB
0156    0B29  20 65 0B              jsr getram            ;read &...
0157    0B2C  85 FC                 sta rbitpatb          ;store it as well
0158    ;
0159    ; 1st test completed & results saved
0160    ;
0161    0B2E  A9 AA                 lda #testpatb         ;2nd test pattern
0162    0B30  A2 00                 ldx #<testadra        ;1st VRAM test address LSB &...
0163    0B32  A0 42                 ldy #>testadra        ;MSB
0164    0B34  20 6B 0B              jsr putram            ;write test pattern
0165    0B37  A2 00                 ldx #<testadra        ;1st VRAM test address LSB &...
0166    0B39  A0 42                 ldy #>testadra        ;MSB
0167    0B3B  20 65 0B              jsr getram            ;read back test pattern &...
0168    0B3E  85 FD                 sta rbitpatc          ;store it for later
0169    0B40  A2 00                 ldx #<testadrb        ;2nd VRAM test address LSB &...
0170    0B42  A0 43                 ldy #>testadrb        ;MSB
0171    0B44  20 65 0B              jsr getram            ;read &...
0172    0B47  85 FE                 sta rbitpatd          ;store it as well
0173    ;
0174    ; 2nd test completed & results saved
0175    ;
0176    0B49  A5 FA                 lda kramregv          ;old KRAM register value
0177    0B4B  A2 1C                 ldx #kramad           ;KRAM & VRAM type reg
0178    0B4D  20 CC CD              jsr writereg          ;restore to original config
0179    0B50  20 27 C0              jsr dlchr             ;restore character patterns in VRAM
0180    ;
0181    ; here we compare the returned test patterns
0182    ;
0183    0B53  A5 FB                 lda rbitpata          ;1st low address returned test value
0184    0B55  C5 FC                 cmp rbitpatb          ;1st high address returned test value
0185    0B57  F0 03                 beq chkvdc02          ;same, possibly 16K VRAM
0186    ;
0187    0B59  A9 40        chkvdc01 lda #ramlarge         ;indicate 64K VRAM
0188    0B5B  60                    rts
0189    ;
0190    0B5C  A5 FD        chkvdc02 lda rbitpatc          ;low address returned test value
0191    0B5E  C5 FE                 cmp rbitpatd          ;high address returned test value
0192    0B60  D0 F7                 bne chkvdc01          ;not same, VDC definitely has 64K VRAM
0193    ;
0194    0B62  A9 10                 lda #ramsmall         ;indicate 16K VRAM
0195    0B64  60                    rts
0196    ;
0197    ;================================================================================
0198    ;
0199    ;read from VRAM
0200    ;
0201    ; .X = VRAM address LSB
0202    ; .Y = VRAM address MSB
0203    ; ---------------------
0204    ; .A = returned byte
0205    ;
0206    ; registers not preserved
0207    ;
0208    0B65  20 71 0B     getram   jsr setadr            ;set VRAM address &...
0209    0B68  4C D8 CD              jmp read80            ;read from VRAM
0210    ;
0211    ;================================================================================
0212    ;
0213    ;write to VRAM
0214    ;
0215    ; .A = byte to write
0216    ; .X = VRAM address LSB
0217    ; .Y = VRAM address MSB
0218    ;
0219    ; registers not preserved
0220    ;
0221    0B6B  20 71 0B     putram   jsr setadr            ;set VRAM address &...
0222    0B6E  4C CA CD              jmp write80           ;write to VRAM
0223    ;
0224    ;================================================================================
0225    ;
0226    ;set up VRAM address
0227    ;
0228    ; .X = VRAM address LSB
0229    ; .Y = VRAM address MSB
0230    ;
0231    ; registers preserved
0232    ;
0233    0B71  48           setadr   pha                   ;preserve registers
0234    0B72  8A                    txa
0235    0B73  48                    pha
0236    0B74  98                    tya                   ;VRAM address MSB
0237    0B75  A2 12                 ldx #vramhi           ;select VRAM address register MSB
0238    0B77  20 CC CD              jsr writereg          ;set address MSB
0239    0B7A  68                    pla                   ;VRAM address LSB
0240    0B7B  A2 13                 ldx #vramlo           ;select VRAM address register LSB
0241    0B7D  20 CC CD              jsr writereg          ;set address LSB
0242    0B80  AA                    tax                   ;restore
0243    0B81  68                    pla                   ;likewise
0244    0B82  60                    rts
0245    ;
0246    ;================================================================================


As I said, VICE is not the proper place to test this program.  It apparently does not account for real hardware subtleties.  Please only report results from testing on the genuine article.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

#13
Quote from: BigDumbDinosaur on January 23, 2008, 06:04 AM
As I said, VICE is not the proper place to test this program.

Indeed. I just wanted people to be aware that testing in VICE would be not only inconclusive, but utterly useless (at least with 1.22 or earlier). Maybe 1.23 will be fixed for this.

Here's an assembled version of your code: vdcramtest.  (moderator's note: this link is dead)

BLOAD "vdcramtest"
BANK 15 : SYS DEC("0B00") : RREG VS
PRINT "This 128 has";VS;"K video RAM."

BigDumbDinosaur

#14
Quote from: Michael Hart on January 23, 2008, 08:05 AM
Quote from: BigDumbDinosaur on January 23, 2008, 06:04 AM
As I said, VICE is not the proper place to test this program.

Indeed. I just wanted people to be aware that testing in VICE would be not only inconclusive, but utterly useless (at least with 1.22 or earlier). Maybe 1.23 will be fixed for this.

Here's an assembled version of your code: vdcramtest.

BLOAD "vdcramtest"
BANK 15 : SYS DEC("0B00") : RREG VS
PRINT "This 128 has";VS;"K video RAM."


Have you tried it on a real 128?

BTW, if you see a lot of my posts with edit dates in them, that's because the drugs I'm on right now to prepare me for surgery are messing with manual dexterity and vision, and I'm having to repeatedly fix typos that are somehow escaping my attention.

Also, there's some kind of a contrast problem with these pages.  The text isn't dark enough relative to the background and I can't do anything to improve the situation.  It particularly causes me problems with narrow letters, such as lower case "L" and "i".  I usually avoid contrast issues when pounding in code by using the traditional "green screen" display in the editor.

Actually, I prefer to blame the interrupt handler that scans the keyboard for messing up my typing, but that excuse probably won't fly.  ;-)
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

Nope, I haven't tried it yet. Even though it's short, I wasn't in the mood to type it in on the real deal as I'm having a heck of a time readjusting to the keyboard after all these years. PCs with huge Backspace keys have rendered my pinky too lazy to stretch all the way to the corner, so on the 128 I drive myself crazy hitting CLR/HOME instead of INST/DEL when trying to fix typos. Maybe someone here wouldn't mind downloading the executable and transferring it over to their machine. If not, I'll type it in later and post again after I've tried it out.

I can relate with having typing issues here, though in my case I think it's due to being constantly sleepy. My asthma medicine really screws with my sleep, but without it I can barely breathe well enough to function. Changing to different medication was pretty disastrous, so I guess I'll take the insomnia and just keep editing my messages to fix typos and wring more sense out of my sentences.

Regarding contrast, have you tried any of the other themes? Lance added a (mostly) black and white theme, and I wonder if that would be easier on your eyes?

BigDumbDinosaur

Quote from: Michael Hart on January 23, 2008, 12:34 PM
Nope, I haven't tried it yet. Even though it's short, I wasn't in the mood to type it in on the real deal as I'm having a heck of a time readjusting to the keyboard after all these years. PCs with huge Backspace keys have rendered my pinky too lazy to stretch all the way to the corner, so on the 128 I drive myself crazy hitting CLR/HOME instead of INST/DEL when trying to fix typos. Maybe someone here wouldn't mind downloading the executable and transferring it over to their machine. If not, I'll type it in later and post again after I've tried it out.

I know what you mean about the Ins/Del key being on the small side.  It has been over 13 years since I touched a 128 keyboard, so I imagine if I ever do again, I'll probably being tripping all over myself.

Quote from: Michael Hart on January 23, 2008, 12:34 PM
I can relate with having typing issues here, though in my case I think it's due to being constantly sleepy. My asthma medicine really screws with my sleep, but without it I can barely breathe well enough to function. Changing to different medication was pretty disastrous, so I guess I'll take the insomnia and just keep editing my messages to fix typos and wring more sense out of my sentences.

Asthma is one of those things where nothing ever works exactly right.  As long as the oxygen going in exceeds the demand, you'll be okay, if a little short of breath.  I had asthma difficulties as a child, and back then, the fast inhalers and such didn't exist.  We had to use a glass nebulizer to get the bronchodilator into a form that could be inhaled.  Fortunately, the asthma  subsided as I got into my teen years and ceased to be a problem.  It was later discovered that my mother's incessant smoking was mostly to blame.

Quote from: Michael Hart on January 23, 2008, 12:34 PM
Regarding contrast, have you tried any of the other themes? Lance added a (mostly) black and white theme, and I wonder if that would be easier on your eyes?

That's the theme I'm using.  It's the least difficult of the bunch.  It could be that the font being used in the edit window is to blame.  There doesn't seem to be a way to change, though.  The contrast is bad.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

Quote from: BigDumbDinosaur on January 23, 2008, 03:10 PM
That's the theme I'm using.  It's the least difficult of the bunch.  It could be that the font being used in the edit window is to blame.  There doesn't seem to be a way to change, though.  The contrast is bad.

Hmm, which browser do you use? Sometimes when I find a site's presentation disagreeable, I override the stylesheet with one I've customized. I'm going to need to do that here since I can hardly read the text in [ code ] blocks.

BigDumbDinosaur

Quote from: Michael Hart on January 23, 2008, 03:38 PM
Quote from: BigDumbDinosaur on January 23, 2008, 03:10 PM
That's the theme I'm using.  It's the least difficult of the bunch.  It could be that the font being used in the edit window is to blame.  There doesn't seem to be a way to change, though.  The contrast is bad.

Hmm, which browser do you use? Sometimes when I find a site's presentation disagreeable, I override the stylesheet with one I've customized. I'm going to need to do that here since I can hardly read the text in [ code ] blocks.

I'm using SeaMonkey.  This is the only site I regularly visit with this problem.  I can live with it for now.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

Update: Went ahead and carefully typed your code in on my flat 128 with unexpanded VDC. As expected, it correctly reported 16K of video RAM.

BigDumbDinosaur

Quote from: Michael Hart on January 23, 2008, 04:20 PM
Update: Went ahead and carefully typed your code in on my flat 128 with unexpanded VDC. As expected, it correctly reported 16K of video RAM.

That's good news.  When the program ran, did you notice any disturbance to the display?
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

Well, I can't actually view 80 column mode reliably (my hacked together cable stinks), so I can't comment on visual disturbances, but on giving the routine and the original it's based on some further thought, I think there could be an unintended consequence on 16K setups like mine.

In Hydrophilic's earlier investigations of VDC addressing, if I understood him correctly, he determined that when 64K mode is set on a VDC with only 16K installed, the following happens to addresses: the high byte is divided by two, and the high nibble is ignored. For example, if you write a value to $1000 or $1100 (or $9000 or $9100), then switch back to 16K mode, you'll find that value at $800. So, it should follow that when writing to $4200 or $4300, the "real" address that is being accessed is $2100. If that is indeed the case, that would usually put us right into character definition territory, and should overwrite the first byte of an upper case 'P'.

But since you didn't mention any such consequence, and I don't know of anyone complaining in all these years that Fred's routine screwed up someone's 'P', I'm going to assume that I probably misunderstood Hydrophilic and went wrong in my analysis somewhere. If I'd remembered to save your program to disk before turning off my 128 (d'oh!), I'd be able to give you a definite answer now, but I'll have to get back to you later after I type it in again and check if KRAM is indeed being written to.

BigDumbDinosaur

Quote from: Michael Hart on January 24, 2008, 04:56 AM
Well, I can't actually view 80 column mode reliably (my hacked together cable stinks), so I can't comment on visual disturbances, but on giving the routine and the original it's based on some further thought, I think there could be an unintended consequence on 16K setups like mine.

In Hydrophilic's earlier investigations of VDC addressing, if I understood him correctly, he determined that when 64K mode is set on a VDC with only 16K installed, the following happens to addresses: the high byte is divided by two, and the high nibble is ignored. For example, if you write a value to $1000 or $1100 (or $9000 or $9100), then switch back to 16K mode, you'll find that value at $800. So, it should follow that when writing to $4200 or $4300, the "real" address that is being accessed is $2100. If that is indeed the case, that would usually put us right into character definition territory, and should overwrite the first byte of an upper case 'P'.

But since you didn't mention any such consequence, and I don't know of anyone complaining in all these years that Fred's routine screwed up someone's 'P', I'm going to assume that I probably misunderstood Hydrophilic and went wrong in my analysis somewhere. If I'd remembered to save your program to disk before turning off my 128 (d'oh!), I'd be able to give you a definite answer now, but I'll have to get back to you later after I type it in again and check if KRAM is indeed being written to.

You are correct in that a write to the two test locations in VRAM on a 16K machine will land smack-dab in the middle of character defintion RAM, causing possible visible screen chaos.  If you look at the source code you will see I have a call to the screen editor's DLCHR ($C027) subroutine immediately after testing has been done.  DLCHR regenerates the VDC's default character definitions, thus undoing the effects of the test.

BTW, I'm hoping that others will read the source code and thus better understand why Fred Bowen's seemingly-convoluted BASIC program is as it is.  When it comes to otherwise uninitialized DRAM, you cannot assume that any given memory cell contains a known bit-pattern.  That is why the double test with the 01010101 ($55) and 10101010 ($AA) bit patterns is performed.
x86?  We ain't got no x86.  We don't need no stinking x86!

nikoniko

#23
Ah, I forgot about the call at the end. Sometimes I hyperfocus on one detail then miss the rest. It's amazing I've never gotten run over in a crosswalk for neglecting to look all ways.

Although it would add a little bit of code, why not stash the original value and restore it? If it's meaningless uninitialized DRAM, no harm done, and if it's meaningful, great, it's much faster than reloading the whole character set. More importantly, the call to DLCHR assumes that the user hasn't loaded a custom character set into VDC RAM prior to running the detection. If they have, we end up trashing it. While it may not affect many people, for those it does that's a pretty nasty side effect from something that's just supposed to report how much RAM is installed. I'm not blaming you at all -- Fred's original does exactly the same thing -- but I really don't think DLCHR is a reasonable shortcut instead of doing right by the end user.

BigDumbDinosaur

Quote from: Michael Hart on January 24, 2008, 08:03 AM
Ah, I forgot about the call at the end. Sometimes I hyperfocus on one detail then miss the rest.

Although it would add a little bit of code, why not stash the original value and restore it? If it's meaningless uninitialized DRAM, no harm done, and if it's meaningful, great, it's much faster than reloading the whole character set. More importantly, the call to DLCHR assumes that the user hasn't loaded a custom character set into VDC RAM prior to running the detection. If they have, we end up trashing it. While it may not affect many people, for those it does that's a pretty nasty side effect from something that's just supposed to report how much RAM is installed. I'm not blaming you at all -- Fred's original does exactly the same thing -- but I really don't think DLCHR is a reasonable shortcut instead of doing right by the end user.

Well, you're assuming that the test write will actually hit the location we think it's going to hit on a 16K machine.  'Tis better to err on the side of caution and reload the defs.  As for a user adding to or replacing the defs, wouldn't it be logical to first run the VRAM size test before doing anything that might change VRAM?  Otherwise, it would be like a program assuming that X amount of memory is there and then try to use it.
x86?  We ain't got no x86.  We don't need no stinking x86!