Previous Thread
Next Thread
Print Thread
Page 3 of 6 1 2 3 4 5 6
Re: c64 super sketch [Re: Golden Child] #116072 10/03/19 03:13 PM
Joined: Feb 2014
Posts: 358
G
Golden Child Online Content OP
Senior Member
OP Online Content
Senior Member
G
Joined: Feb 2014
Posts: 358
In searching for info about the supersketch I came across the VersaWriter which was a similar device that used an arm with two sections that would use potentiometer analog inputs to calculate the position of the tip.

These were used by Roberta Williams and Jordan Mechner in making their games.

[Linked Image from i.imgur.com]

https://www.filfre.net/2011/10/mystery-house-part-1/

https://www.museumofplay.org/blog/c...on-documents-revolution-in-game-graphics


Some nice pictures here of the apple and atari versions:

https://atariage.com/forums/topic/293821-i-have-a-versawriter-i-am-trying-to-evaluate/

And an ad for the pc version:

[Linked Image from i.imgur.com]

They had these for the Apple 2, atari, pc (that I know of). I was able to find a disk image for the Atari 800 and set out to figure how it worked.

Let's start "vestigating"


If I run the atari disk image under the 800xl driver it will hang up while trying to read the controller ports. If I hit joystick right and left quickly that will "unstick" it so that gives us some hints.



[Linked Image from i.imgur.com][Linked Image from i.imgur.com]

Analyzing it, it appears that this is reading a potentiometer input by writing to $d300 a strobe with 30, choosing the axis to read with 20 or 10, then hitting the strobe again with 30. It uses the X and Y registers to hold a 16bit value, counts until the $d300 input goes low, then returns the count in 4ffe/4fff.

Putting them side by side, the x axis gets read with 30,20,30 and then anding $d300 with $40, exiting when bit 6 clears.
The y axis gets read with 30,10,30 and then anding $d300 with $80, exiting when bit 7 clears.


Why they didn't use the potentiometer input on the atari is a bit baffling. It's got paddle inputs so why not use them?


add some various bits to a400_state:

Code
                m_mypot0(*this, "myanalog_0"),
                m_mypot1(*this, "myanalog_1")

        DECLARE_READ8_MEMBER(a800xl_d300_read);
        DECLARE_WRITE8_MEMBER(a800xl_d300_write);

double m_versatime;



Our d300 read routine:
Code

READ8_MEMBER(a400_state::a800xl_d300_read)
{
if (machine().time().as_double() > m_versatime) return 0;
return 0xff;
}

WRITE8_MEMBER(a400_state::a800xl_d300_write)
{
        if (data==0x10) { m_versatime = machine().time().as_double() + attotime::from_nsec(50000).as_double()*m_mypot0->read();}
       if (data==0x20) {  m_versatime = machine().time().as_double() + attotime::from_nsec(50000).as_double()*m_mypot1->read();}
}



Modify the address map:

Code
void a400_state::a800xl_mem(address_map &map)
{
        map(0x0000, 0xcfff).rw(FUNC(a400_state::a800xl_low_r), FUNC(a400_state::a800xl_low_w));
        map(0xd000, 0xd0ff).rw(m_gtia, FUNC(gtia_device::read), FUNC(gtia_device::write));
        map(0xd100, 0xd1ff).noprw();
        map(0xd200, 0xd2ff).rw("pokey", FUNC(pokey_device::read), FUNC(pokey_device::write));
        map(0xd300, 0xd3ff).rw(m_pia, FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
// insert our d300 read and write routine
        map(0xd300, 0xd300).rw(FUNC(a400_state::a800xl_d300_read), FUNC(a400_state::a800xl_d300_write));    
        map(0xd400, 0xd4ff).rw(m_antic, FUNC(antic_device::read), FUNC(antic_device::write));
        map(0xd500, 0xd7ff).noprw();
        map(0xd800, 0xffff).rw(FUNC(a400_state::a800xl_high_r), FUNC(a400_state::a800xl_high_w));
}


add some analog inputs:
Code
     PORT_START("myanalog_0")
        PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) PORT_NAME("myanalog_0")

        PORT_START("myanalog_1")
        PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) PORT_NAME("myanalog_1")



and now when you get the analog just right, you can see by moving just the x or the y axis that it will "sweep" in a circular motion.

The 1 key draws, space to turn off drawing.

[Linked Image from i.imgur.com]

Re: c64 super sketch [Re: Golden Child] #116073 10/03/19 04:48 PM
Joined: Feb 2004
Posts: 2,095
Vas Crabb Offline
Very Senior Member
Offline
Very Senior Member
Joined: Feb 2004
Posts: 2,095
If you're going to emulate that device, you should have the option for MAME to do the inverse kinematic transform for you so X/Y work intuitively. It's not too difficult in two dimensions.

Re: c64 super sketch [Re: Golden Child] #116075 10/03/19 07:58 PM
Joined: Mar 2006
Posts: 1,035
L
Lord Nightmare Offline
Very Senior Member
Offline
Very Senior Member
L
Joined: Mar 2006
Posts: 1,035
Originally Posted by Golden Child

...
Why they didn't use the potentiometer input on the atari is a bit baffling. It's got paddle inputs so why not use them?
...


My guess is because of the infamous 'pokey bug':
As I understand it, the pokey ADC works by slowly charging the analog input pin via an on-die(?) resistor, and incrementing(?) an 8 bit counter until the voltage read from the pin hits a threshold, then stopping the counter, dumping the pin back to ground via a transistor, waiting a bit, then resetting the register to zero(?) and repeating.

if you read from the ADC input register while it is still counting up, you will read a bogus/invalid value, and there's no way to tell whether you're reading it in one of the 'bad' states or not. Most games which used the Pokey analog inputs worked around this by reading the ADC 3 or 5 times and 'voting' on which values were valid by majority.

The 1983 star wars arcade game famously still does this on its analog inputs even though the programmers got frustrated enough with the pokey analog reading that they switched to using dedicated analog devices ADC chips instead! They left the input voting/smoothing code in there and active by accident!

The commodore SID doesn't have this issue, since it uses two separate registers (really a counter and an 8 bit latch) for reading the analog/paddle inputs, and latches the value when the voltage threshold is reached, so the register never reads as invalid garbage. Why Atari didn't do this on the pokey is unknown.

It is actually possible that the pokey does have a separate 8-bit adc latch, but due to some state machine screwup elsewhere it sometimes gets stuck in a transparent or otherwise bogus state.

The pokey die schematics can be found at http://www.atarimuseum.com/archives/chips/pokey.zip but I have not investigated the way the ADC actually works very deeply; the information above is based mostly on other sources (asking people on IRC, etc).

EDIT2: looking at the pot scan circuitry schematics on page C012294-3, it at least seems like my assessment was largely correct: there's an array of 8 hysteresis/level compare circuits for the 8 pot inputs, and an 8x8 array of what seem to be counters storing the current count from each of those inputs, multiplexed using a single 4 or 8 bit counter (4 bits in fast mode, 8 bits in slow mode), and no 'latch' other than the fact that 7/8ths of the time one of the other counters is being incremented.

Last edited by Lord Nightmare; 10/03/19 08:12 PM.

"When life gives you zombies... *CHA-CHIK!* ...you make zombie-ade!"
Re: c64 super sketch [Re: Golden Child] #116076 10/03/19 08:04 PM
Joined: Mar 2001
Posts: 16,394
R
R. Belmont Online Content
Very Senior Member
Online Content
Very Senior Member
R
Joined: Mar 2001
Posts: 16,394
Alternatively it's possible they wanted to use the same hardware with the same pots on all systems and the values weren't amenable to the POKEY's ADC hardware.

Re: c64 super sketch [Re: Lord Nightmare] #116109 10/05/19 07:30 PM
Joined: Feb 2014
Posts: 358
G
Golden Child Online Content OP
Senior Member
OP Online Content
Senior Member
G
Joined: Feb 2014
Posts: 358
That's an interesting story about the "Pokey bug". I guess hardware has bugs just like software.

I was thinking about how awesome the pokey chip was to have 8 channels of paddle inputs that get read in hardware every screen frame, enough so that you could have 4 analog joysticks. I'm guessing that the Atari 5200 must have used the pokey to read the analog joystick controllers since the original 5200 had 4 controller ports.

According to a post on atariage: "The XL/XE as well as the 2600 is - without any tricks - capable of reading a twin-axis analog input device with up to five buttons - closest to that in existence is the Touch Tablet with its 3 buttons. Many more digital inputs for the same two ports are possible - cf. 2600 keyboard controllers, Multijoy8 and Multijoy16 - with specially programmed software."


===

Back to the versawriter, I think I've figured out the trigonometry to do the calculation, but it'd be good to know the exact dimensions of the arms, I'm guessing somewhere between 4 and 5 inches long. I think the arm pivot must be about 1 inch from the top of the image holder. Anybody have a versawriter to do the measurements?


Atari Basic is quirky, but I managed to get it to display the contents of the VWCALDA7.VER and VWCALDA8.VER files which are the calibration values to feed to the drawing programs. There are two different sets of calibration values, one for graphics 7 and one for graphics 8, as I guess that the paddle reading takes different timing on the different modes.


[Linked Image from i.imgur.com]

The first 4 values in the file are the load address and the length of the file, the load address being $600 and the length being 8 bytes.

I try to run the calibration program with my emulated paddles and it can't seem to write to the disk properly, giving me an error #138 (device not ready).


[Linked Image from i.imgur.com][Linked Image from i.imgur.com]

It pokes the values into memory at $600 so let's just save them out with the debugger command "save cal.bin,600,8" , and after loading the drawing program with

RUN "D:VWSOFTG8.BAS

or

RUN "D:VW

then loading the calibration data with "load cal.bin,600"

[Linked Image from i.imgur.com]


So far I can make it do this:

[Linked Image from i.imgur.com]

This is moving up and down and left and right with the mouse. It's not perfect, a little bit wiggly, but we're getting closer.


BTW what is the BACKSLASH2 key? That's what the atari driver maps to backspace by default. Somewhere I read that's a key on international keyboards, something about oem_102?. After making do without the backspace key for awhile, I finally mapped it to the "real" backspace key.


While searching around for atari keyboard layouts I came across this layout, it's so pretty. One day it'd be awesome if mame could have an onscreen keyboard that looks like this.

[Linked Image from i.imgur.com]

https://www.keyboard-design.com/layouts/60/Atari-800.html

Re: c64 super sketch [Re: Golden Child] #116122 10/06/19 09:26 PM
Joined: May 2004
Posts: 890
D
Duke Offline
Senior Member
Offline
Senior Member
D
Joined: May 2004
Posts: 890
BACKSLASH2 is the key to the left of the Z key:

[Linked Image from kbd-intl.narod.ru]

Re: c64 super sketch [Re: Golden Child] #116123 10/06/19 09:27 PM
Joined: Mar 2001
Posts: 16,394
R
R. Belmont Online Content
Very Senior Member
Online Content
Very Senior Member
R
Joined: Mar 2001
Posts: 16,394
Right. BACKSLASH2 doesn't exist on US-ANSI keyboards, so mapping things to it is as much of a mistake as my trying to use LWIN.

Re: c64 super sketch [Re: Golden Child] #116188 10/16/19 07:35 PM
Joined: Feb 2014
Posts: 358
G
Golden Child Online Content OP
Senior Member
OP Online Content
Senior Member
G
Joined: Feb 2014
Posts: 358
So let's figure out how do get an Atari 800 screendump so we can really study VWCALSFT.BAS. There doesn't seem to be a printer for the Atari 800 driver, so we'll just do LIST and then pause the listing by toggling CTRL+1.

A little lua script for screendump:

Code
function ram(adr) return emu.item(manager:machine().devices[":ram"].items["0/m_pointer"]):read(adr) end
function between(c,a,b) return a<=c and c<=b end
function boffset(x,y) return y*40+x end
function scrascii(c) c=c&0x7f 
   if between(c,0,0x3f) then return c+0x20 end 
   if c==0x7f then return 32 end 
   if between(c,0x60,0x7f) then return c end 
   if between (c,0x40,0x5f) then return string.byte("*") end 
end
function scrdump(startcol) startcol = startcol or 2 for y=0,23 do for x=startcol,39 do io.write (string.char(scrascii(ram(boffset(x,y)+ram(88)+ram(89)*256)))) end print () end end

-- a little test of our screendump
emu.keypost([[100 PRINT CHR$(125):FOR I=0 TO 5:PRINT:NEXT I:FOR I=0 TO 255:POKE I+PEEK(88)+PEEK(89)*256,I:NEXT I
   RUN
]])
scrdump(0)


With a little bit of stitching we get a nice listing, though CHR$(125) doesn't come through so that was added manually.

Code
READY                                 
LOAD "D:VWCALSFT.BAS                  
                                        
READY                                 
LIST                                  
                                        
                                                       
100 GRAPHICS 8:POKE 752,1             
110 DIM P8(8),P7(8),FS$(16),IO$(1)    
120 N127=127:N947=947                 
130 LGTHL=8:LGTHH=0:AUX2=0            
140 FS$="D:VWPDIV03.VER":AUX1=4:PTGT=7:GOSUB 30500                          
200 POKE 54018,56:POKE 54016,48:POKE 54018,60                               
430 POKE 20245,N0:POKE 20254,N0:POKE 20262,N0:POKE 20268,N0:POKE 20303,N0:POKE 20312,N0                           
440 POKE 20320,N0:POKE 20326,N0       
2000 BS=1:POKE 764,255                
2100 PRINT CHR$(125);                       
2105 IF BS>=5 THEN 3000               
2110 PRINT "POSITION ARMS AS SHOWN IN DIAGRAM ";BS                          
2120 PRINT "PADDLE(0)=         PADDLE(1)=  "                                
2125 PRINT :PRINT "PRESS SPACE BAR WHEN READY";                             
2130 BS=BS+1                          
2140 GRAPHICS 8+32:POKE 752,1:SETCOLOR 2,0,0                                
2150 GOSUB 6000                       
2160 P8(BS-2)=P0:P8(BS+2)=P1          
2170 GRAPHICS 7+32:POKE 752,1:SETCOLOR 2,0,0                                
2180 GOSUB 6000                       
2190 P7(BS-2)=P0:P7(BS+2)=P1          
2200 POKE 656,1:POKE 657,12:PRINT P0;"   ";:POKE 657,31:PRINT P1;"   ";     
2210 IF PEEK(764)=255 THEN 2140       
2220 POKE 764,255                     
2300 PRINT CHR$(125):FOR WT=1 TO 130:NEXT WT:GOTO 2100                            
3000 PRINT CHR$(125);"CALIBRATION IS COMPLETE ":TRAP 5500                         
3010 A=P8(0):B=P8(1):FLG=0:GOSUB 5000 
3020 POKE 1536,SL:POKE 1537,SH:POKE 1538,OL:POKE 1539,OH                    
3030 A=P8(6):B=P8(7):FLG=1:GOSUB 5000 
3050 POKE 1540,SL:POKE 1541,SH:POKE 1542,OL:POKE 1543,OH                    
3060 FS$="D:VWCALDA8.VER":ADDL=0:ADDH=6:AUX1=8:PTGT=11:GOSUB 30500          
3100 A=P7(0):B=P7(1):FLG=0:GOSUB 5000 
3120 POKE 1536,SL:POKE 1537,SH:POKE 1538,OL:POKE 1539,OH                    
3130 A=P7(6):B=P7(7):FLG=1:GOSUB 5000 
3150 POKE 1540,SL:POKE 1541,SH:POKE 1542,OL:POKE 1543,OH                    
3160 FS$="D:VWCALDA7.VER":ADDL=0:ADDH=6:AUX1=8:PTGT=11:GOSUB 30500          
3600 TRAP 40000:RUN "D:VW"            
3610 END                              
5000 IF A>=B THEN POP :GOTO 5500      
5050 S0=8192/(B-A)                    
5060 IF FLG=1 THEN O0=S0*B:GOTO 5100  
5070 O0=16384+S0*B                    
5100 SH=INT(S0)                       
5110 SL=INT((S0-SH)*256+0.5)          
5120 OV=INT(O0+0.5)                   
5130 OH=INT(OV/256)                   
5140 OL=OV-OH*256                     
5200 RETURN                           
5500 GRAPHICS 0:PRINT "ERROR IN ARM PLACEMENT----"                          
5510 PRINT "PLEASE REVIEW THE INSTRUCTIONS AND"                             
5520 PRINT "THEN REBOOT THE DISK TO TRY AGAIN."                             
5530 PRINT :END                       
6000 W=USR(20224)                     
6010 P0=PEEK(20478)+256*PEEK(20479)   
6020 W=USR(20228)                     
6030 P1=PEEK(20478)+256*PEEK(20479)   
6040 RETURN                           
30500 FOR X=1 TO LEN(FS$):POKE 1599+X,ASC(FS$(X,X)):NEXT X                  
30600 POKE 1616,AUX1:POKE 1617,AUX2:POKE 1618,PTGT                          
30605 POKE 1408,ADDL:POKE 1409,ADDH:POKE 1410,LGTHL:POKE 1411,LGTHH         
30610 M=USR(1624):IF PEEK(N947)>N127 THEN 30900                             
30630 M=USR(1627):IF PEEK(N947)>N127 THEN 30900                             
30635 M=USR(1630):IF PEEK(N947)>N127 THEN 30900                             
30640 M=USR(1633):IF PEEK(N947)>N127 THEN 30900                             
30650 RETURN                          
30900 TEMP=PEEK(N947):M=USR(1633)     
30910 GRAPHICS 0:PRINT "I/O ERROR # ";TEMP:POP                              
30920 IF TEMP<>167 THEN 30960         
30930 PRINT "HAVE YOU LOCKED 'VWCALDA8.VER' AND "                           
30940 PRINT "'VWCALDA7.VER?"          
30950 PRINT "PLEASE UNLOCK AND REBOOT THE DISK":END                         
30960 PRINT "REBOOT THE DISK WHEN THE PROBLEM"                              
30970 PRINT "IS RESOLVED."            
30980 END                             
                                      
READY                                 



We read the paddles under two different graphics modes, graphic mode 8 and graphic mode 7.
The 32 is added to not clear the screen (probably to speeds up the switching).

Coming in BS starts at 2, and gets incremented on each pass.

The BS-2 and BS+2 indexes put paddle0 values in indexes 0 to 3, and paddle1 values in indexes 4 to 7.

Diagram 1 : P8(0)=paddle0 P8(4)=paddle1
Diagram 2 : P8(1)=paddle0 P8(5)=paddle1
Diagram 3 : P8(2)=paddle0 P8(6)=paddle1
Diagram 4 : P8(3)=paddle0 P8(7)=paddle1

The P8 array is filled out while under graphics 8 mode.
The P7 array is filled out while under graphics 7 mode.

Code
2140 GRAPHICS 8+32:POKE 752,1:SETCOLOR 2,0,0                                
2150 GOSUB 6000                       
2160 P8(BS-2)=P0:P8(BS+2)=P1          
2170 GRAPHICS 7+32:POKE 752,1:SETCOLOR 2,0,0                                
2180 GOSUB 6000                       
2190 P7(BS-2)=P0:P7(BS+2)=P1     


gosub 6000 is our routine to read paddle0 and paddle1,
$4f00=20224 to read paddle0 and $4f04=20228 to read paddle1, returning the 16 bit paddle values in $4ffe and $4fff (20478 and 20479)

Code
6000 W=USR(20224)                                           
6010 P0=PEEK(20478)+256*PEEK(20479)   
6020 W=USR(20228)                     
6030 P1=PEEK(20478)+256*PEEK(20479)   
6040 RETURN             


Now here's where things get calculated:
Diagram 1 and 2 serve to calibrate paddle 0.
Diagram 3 and 4 serve to calibrate paddle 1.

A gets set to paddle0 for diagram 1.
B gets set to paddle0 for diagram 2.

Then we set FLG=0 and gosub 5000 to do the heavy calculating.

Code
3010 A=P8(0):B=P8(1):FLG=0:GOSUB 5000 
3020 POKE 1536,SL:POKE 1537,SH:POKE 1538,OL:POKE 1539,OH                    

A gets set to paddle1 for diagram 3.
B gets set to paddle1 for diagram 4.
Set FLG=1 and GOSUB 5000 to do the heavy calculating.
Code
3030 A=P8(6):B=P8(7):FLG=1:GOSUB 5000 
3050 POKE 1540,SL:POKE 1541,SH:POKE 1542,OL:POKE 1543,OH                    
3060 FS$="D:VWCALDA8.VER":ADDL=0:ADDH=6:AUX1=8:PTGT=11:GOSUB 30500    


If A>=B then error out and goto 5550. B must always be greater than A or it doesn't make sense.
We calculate our scale with 8192/(B-A).
We calculate our origin with 16384 + scale * B for paddle0 or scale * B for paddle1, depending on how FLG is set.
IF FLG=1 THEN O0=S0*B
else O0=16384+S0*B.


Code
5000 IF A>=B THEN POP :GOTO 5500      
5050 S0=8192/(B-A)                    
5060 IF FLG=1 THEN O0=S0*B:GOTO 5100  
5070 O0=16384+S0*B                    
5100 SH=INT(S0)                       
5110 SL=INT((S0-SH)*256+0.5)          
5120 OV=INT(O0+0.5)                   
5130 OH=INT(OV/256)                   
5140 OL=OV-OH*256                     
5200 RETURN            
     


These calculations are done beforehand so later all we have to do is a 16bit x 16bit multiply, as the division by (B-A) is done for us (we are just multiplying by the reciprocal of (B-A)).

Re: c64 super sketch [Re: Golden Child] #116191 10/17/19 12:54 AM
Joined: Feb 2014
Posts: 358
G
Golden Child Online Content OP
Senior Member
OP Online Content
Senior Member
G
Joined: Feb 2014
Posts: 358
So once we have these equations, we can make a spreadsheet, and with a bit of trial and error, deduce what the original values of the paddles when it was calibrated.

The values in VWCALDA8.VER are 58,20,193,115,84,20,70,70.


[Linked Image from i.imgur.com]

We find that PDL0 was A=250 and B=655, and PDL1 was A=482 and B=885.

[Linked Image from i.imgur.com]

the formulas in the sheet:

[Linked Image from i.imgur.com]


[Linked Image from i.imgur.com]


From a cool article on the versawriter, I now know the length of the arms: 6 inches each and the dimensions of the main board: it measures 12" vertically and 13.5" horizontally.

ATARI CLASSICS Volume 2, Issue 3 / June 1993 / PAGE 26
LOOKiNG BACK: WHAT IS VERSAWRITER?
GARY MATTESON AC STAFF REVIEWER

https://www.atarimagazines.com/atariclassics/v2n3/looking_back.php

Re: c64 super sketch [Re: Golden Child] #116214 10/18/19 02:36 PM
Joined: Feb 2014
Posts: 358
G
Golden Child Online Content OP
Senior Member
OP Online Content
Senior Member
G
Joined: Feb 2014
Posts: 358
Just posting my analysis of the versawriter reading routines:

PADDLE 0 computation

scale=(8192/(B-A))
origin=16384+(8192/(B-A))*B

8192 = 32 * 256

0 = 0x0000 0 * 256 = 0 degrees
8192 = 0x2000 32 * 256 = 90 degrees
16384 = 0x4000 64 * 256 = 180 degrees
24576 = 0x6000 96 * 256 = 270 degrees

take x, multiply x by scale, subtract that value from origin:
origin - scale * pdl = angle of position

origin - scale * pdl = angle

if pdl=B: 16384 + (8192/(B-A))*B - 8192/(B-A))*B = 16384 + 0 (since B-B=0) or 180 degrees

if pdl=A: 16384 + (8192/(B-A))*B - 8192/(B-A))*A = 16384 + 8192*(1) (since (B-A)/(B-A)=1) or 270 degrees

this result is the angle that arm 1 is pointing in (with angle=0 pointing right on the x axis).

PADDLE 1 computation
exactly the same but we don't add 16384 to the origin:

scale=(8192/(B-A))
origin=(8192/(B-A))*B


origin - scale * pdl = angle

if pdl=B: (8192/(B-A))*B - 8192/(B-A))*B = 8192 * 0 (since B-B=0) or 0 degrees

if pdl=A: (8192/(B-A))*B - 8192/(B-A))*A = 8192*(1) (since (B-A)/(B-A)=1) or 90 degrees



so the resulting angle direction is the angle from paddle 0 + angle from paddle 1 = direction that arm 2 is pointing.


The x and y coordinates are initialized to $4000,$4000 (one of the final steps is to divide this coordinate by 32 so this can be treated as 2.0,2.0).

x=2.0*32;y=2.0*32;

We read paddle0, take the precomputed origin value and subtract scale*pdl0. Now we have a value for angle0 and we add cos(angle0) to x and sin (angle0) to y. Our sine table is pre-multiplied by 32 and this value of 32 represents 1.0 multiplied by our arm length of 6.0 inches. (we can treat our sin/cos as "unit circle values" where each unit represents 6.0 inches).
The code to handle sin also calculates cos from the sin table by using cos theta=90-sin theta by eor the angle with #$1FFF (one's complement, effectively subtracting the angle 0-1fff from 90). All the values in the sine table are positive so we add or subtract from x or y depending on the quadrant.

Our sin table is 4096 bytes/2 bytes per entry for 2048 entries over 90 degrees.
Dividing 90 degrees / 2048 steps gives a resolution of .05 degree.

angle0 = origin0 - scale0 * pdl0;
x+=cos(angle0);y+=sin(angle0);

Paddle1 is then read, and the precomputed origin value is taken and scale*pdl1 is subtracted:
Then this angle1 is added to angle0 so we are "turning" left from the direction pointed by angle0.

angle1 = (origin1 - scale1*pdl1);
angle1 += angle0;
x+=cos(angle1);y+=sin(angle1);

The final steps are to scale our resulting x/y coordinates to screen coordinates.

We divide by 32;

x >>= 5;
y >>= 5;

Subtract 0x1ea8 from x, 0x4aa8 from y.

x-=0x1ea8; this has the effect of subtracting 0.95
y-=0x4aa8; this has the effect of subtracting 2.33

Then multiply by 0x990e and 0x7740.

x*=0x990e; this multiplies by 153.05 (153.05 * 2 = 306, very close to horizontal resolution of 320)
12 inches mapped to 306 pixels (25.5 pix/inch))
y*=0x7740; this multiplies by 119.25 (119.25 * 1.67 = 198.73, very close to vertical resolution of 192)
(119.25 * 1.33 = 159, matches visible vertical resolution of 160
with 4 text lines at the bottom
and it's 8 inches mapping to 160 pixels
(20 pix/inch))

x coordinate before subtracting 0.95 runs from (1.0 to 3.0, or 2-1 to 2+1).
y coordinate before subtracting 2.33 runs from (2.0 to 4.0, or 2,2+1+1).

x coordinate of 1.0 becomes screen x = 6
x coordinate of 3.0 becomes screen x = 312

y coordinate of 2.33 becomes screen y = 0
y coordinate of 3.67 becomes screen y = 159



The versawriter reading code at $4c00-$4dff implements 16 bit addition ($4d2e) and 16 bit subtraction ($4d1a) routines using two 16 bit "registers" at $610/611 (ACC1) and $612/613 (ACC2). $4d2e does ACC1 += ACC2, AND $4d1a does ACC1 -= ACC2;

There is a routine to do 16 bit x 16 bit multiply with a 32 bit result ($4d42), multiplicand in cf,d0, multiplier in cb,cc, with results in cb,cc,cd,ce cb=lowest byte ce=highest byte.

After writing up my routine to feed the paddle values to the versawriter code, I was still getting wacky results, which was driving me wacky, so I thought, why not make sure it's getting the correct values so I decided to just stuff the value in 4dfc/4dfd and patching the paddle read routine to just copy these values into 4dfe/4dff.

Analog reading by the versawriter routine:
[Linked Image from i.imgur.com]

Directly plugging the analog values into memory:
[Linked Image from i.imgur.com]


Lo and behold I get "perfect" straight axis lines. Something is affecting the timing of the read routine. At the beginning of the read routine, there's code to busy-wait until we are on scanline #1 (waiting for VCOUNTER=1), so that should allow the analog read to have consistent timing. Somehow this isn't working correctly. Interestingly, the variation in reading is very consistent, it tracks the exact same weird paths.

So I guess there's more mysteries to be solved.

Page 3 of 6 1 2 3 4 5 6

Who's Online Now
1 registered members (Stiletto), 222 guests, and 0 spiders.
Key: Admin, Global Mod, Mod
ShoutChat Box
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics8,722
Posts114,651
Members4,873
Most Online510
Aug 26th, 2019
Powered by UBB.threads™ PHP Forum Software 7.7.3