Thema: RE: Yea...! Datum: 14.10.96 14:26:54 From: wilki1k@nectech.co.uk (Wilkins, Keith) To: Chrissalo@aol.com (Chrissalo) Chris, > Just a small letter to keep you informed of what I'm doing... Thanks. I saw your posting to r.g.v have you had any response ?? I never had any response to the request in the readme for technical info on the light pen or 3D imager. > Two new Screen resolutions added (just for fun). Now 256 Colour mode > for 1280x1024 and 1600x1200 (!!!) can be chosen as mode 3 and 4! Cool. > (though the shots of minestorm are hard to make out :-)). > (new scaling added, exact (using DIV instruction) and 'not exact' (your shift Thats why I used the shift, but now you've gained some improvement its easy to give a little back to use a divide. Shift is annoying because of the innacuracies hence the reason for 2 shifts and an add. Whats the speed hit when using DIV. > I did this thing you suggested to the sequencer I called it > MultiTick6809 emulation... nice speed increase for such a 'little' thing. I would have thought you might have got more than 9% but thats a respectable improvement. I suppose its all based on how often you can use multitick. > (actually it's hard to get into some others code so progress is still > sort of slow)... I had a couple of strange errors... Tell me more and I'll see if I can help. > I did try a few guesses at integrators... Are you sure it's their > perfectness? I know they should be leeking a bit, but I'm not sure if Its not the leaking thats the problem. What you effectively have is an R/C (Resistor/Capacitor) charge circuit and the result is an exponential curve. As the capacitor gets closer to full charge the rate of charge slows down. So you get a fast ramp at the beginning which tails off when the integrator voltage gets near to the supply rails i.e The further out from the centre you go the worse the error is. The point at which I found this was when I was debugging Clean Sweep (one of the worst). The game draws the screen in two passes. Horizontal & Vertical. Line lenght is set by two things: DAC Value & Integration time. For DVE: length = DAC * Time A lot of programs use a constant time value and vary the DAC value as this ensures that your vectors will always meet. Clean Sweep uses different time values for horiztonal & vertical drawing. The start points should be the same when you multiply DAC * Time. I went through the data tables and the start points for H&V have been "tweaked" for the inaccuracies i.e not the same. At least thats what I think, I could be wrong. > thats the point... I rather guess it has something to do with > 'lwGblSystemTickTotal' not allways being in the correct state for > correct emulation. Or perhaps it is that digital DAC of yours... > At one point I had all objects (which were drawn straight after another > (without reseting the integrators)) correct. The other 'reseting' objects > (like score or writtings) 'incorrect' (every other line to far to one > side...). I can't picture it in my mind. Why not zip the source & exe and email them to me and I'll take a look. I'd love to see the higher res modes. > Your version is something about 44% my newest version does > about 70%. Thanks to your tip with multitick... Nice. > Perhaps the next thing I'll do is that lightpen emulation Good luck. > BTW: > A couple of month ago you send me some copy of vectrex materials > the copy of the service manual is incomplete :-( Ooops. I'll blame the office photocopier. I'll try and copy them again. Regards Keith P.S Here's the joystick code from the Stella terminal class I wrote. The bits you want are in the following functions: Terminal::Terminal(const Properties& properties) - Initialisation & timout calibration void Terminal::handleEvents() - Read loop [[ TermDOS.cxx : 3356 in TermDOS.cxx ]] ///////////////////////////////////////////////////////////////////////////// // $Id:$ ////////////////////////////////////////////////////////////////////////////// // Stella 96 // "An Atari 2600 Simulator" // Copyright (c) 1995,1996 // Bradford W. Mott ////////////////////////////////////////////////////////////////////////////// // // Terminal // // This class provides a standard API for the screen. This file contains // the DOS VGA implementation of the API. // // (c) Keith Wilkins // May 17,1996 // ////////////////////////////////////////////////////////////////////////////// // $Log:$ ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include "error.hxx" #include "colors.h" #include "Term.hxx" #include "TIA.hxx" // Indicates if an instance is alive bool Terminal::ourInstanceCreated = false; // Contains the state of each of the events based on the keyboard static volatile uLong theKeyboardEventState[TERMINAL_NUMBER_OF_EVENTS]; // Contains the state of each of the events based on the Joystick static volatile uLong theJoystickEventState[TERMINAL_NUMBER_OF_EVENTS]; // // Mouse IRQ and button definitions // #define MOUSE_LEFT_BUTTON 0x0001 #define MOUSE_RIGHT_BUTTON 0x0002 #define MOUSE_CENTRE_BUTTON 0x0004 #define MOUSE_BUTTON_MASK 0x0007 #define MOUSE_INT 0x33 // // VGA Card definitions and locals // #define VGA_BIOS 0x10 #define VGA_MISC_OUTPUT_W 0x03c2 #define VGA_MISC_OUTPUT_R 0x03cc #define VGA_SEQ_CONTROL 0x03c4 #define VGA_CRTC_CONTROL 0x03d4 #define VGA_INPUT_STATUS 0x03da #define VGA_PEL_ADDRESS 0x03c8 #define VGA_PEL_DATA 0x03c9 static word default_term_mode; static uWord thePixelDataTable[256]; // Indicates the width and height based on the property information static uLong theWidth; static uLong theHeight; static uLong theXStart; // // Joystick definitions // #define GAME_PORT 0x0201 static uLong joypresent=0; static uLong joytimeout=0; static Long joymin[4]={65536,65536,65536,65536}; static Long joymax[4]={0,0,0,0}; static Long joyzero[4]={0,0,0,0}; static Long joytrig[4]={16384,16384,16384,16384};; // // Scan code defines // #include "scandef.h" static void (__interrupt __far *old_key_handler)(); static void __interrupt __far kbd_int_handler(void); ////////////////////////////////////////////////////////////////////////////// // Constructor ////////////////////////////////////////////////////////////////////////////// Terminal::Terminal(const Properties& properties) :myProperties(&properties) { union _REGS regs; assert(!ourInstanceCreated); ourInstanceCreated = true; // Clear the terminal event state for(int i = 0;i < TERMINAL_NUMBER_OF_EVENTS; i++) { theKeyboardEventState[i] = 0; theJoystickEventState[i] = 0; } // Lets save the current mode regs.h.ah = 0x0f; int386(VGA_BIOS, ®s, ®s); default_term_mode = regs.h.al; // Plop into 320x200x256 mode 13, maybe chain-X later..... if(!_setvideomode(_MRES256COLOR)) { cerr << "ERROR: Failed to set video mode to 320x200x256" << endl; } // Setup the pixel data table for(uLong j = 0; j < 256; ++j) { thePixelDataTable[j] = j | (j << 8); } // Get the desired width and height of the display theWidth = myProperties->integer("Display.Width"); theXStart = myProperties->integer("Display.XStart"); theHeight = myProperties->integer("Display.Height"); // Set colour pallete direct to the card as the Watcom functions // take far to long because they wait for a retrace, bummer outp(VGA_PEL_ADDRESS,0); // Start from pen 0 for(int index = 0; index < 256; index++) { outp(VGA_PEL_DATA,(theColorTable[index] & 0x00ff0000) >> 18); outp(VGA_PEL_DATA,(theColorTable[index] & 0x0000ff00) >> 10); outp(VGA_PEL_DATA,(theColorTable[index] & 0x000000ff) >> 2); } // Now steal the keyboard interrupt from DOS, honest guv I'll // give it back later..... old_key_handler = _dos_getvect(0x09); _dos_setvect(0x09, kbd_int_handler); // Initialise/reset mouse handler via DOS interrupt // Set bound box 0,0 to 511,511 in X & Y regs.x.eax = 0x0000; int386(MOUSE_INT, ®s, ®s); if (regs.x.eax!=0xffff) { cerr << "ERROR: Mouse initialisation failed" << endl; } regs.x.eax = 0x0007; regs.x.ecx = 0; regs.x.edx = 511; int386(MOUSE_INT, ®s, ®s); regs.x.eax = 0x0008; regs.x.ecx = 0; regs.x.edx = 511; int386(MOUSE_INT, ®s, ®s); // Determine if a joystick is present in the system // GAME PORT Bit description (strictly for laughs) // // Bit 0 - JoyA X-Axis // Bit 1 - JoyA Y-Axis // Bit 2 - JoyB X-Axis // Bit 3 - JoyB Y-Axis // Bit 4 - JoyA Button 1 // Bit 5 - JoyA Button 2 // Bit 6 - JoyB Button 1 // Bit 7 - JoyB Button 2 uByte joyinp; outp(GAME_PORT,0); // Frag the joy port and wait for low on all lower 4 pins // timeout if things take more than 500ms. // Use the DOS timers - yuck time_t start=clock(); while(1) { joyinp=inp(GAME_PORT); joyinp&=0x0f; // Joystick latches low indicate completion of conversion if(!joyinp) { break; } if((clock()-start) > (CLOCKS_PER_SEC/2)) { break; // Timeout on joystick } } // Setup joypresent mask tells which axis are present // this will stop searches on unconnected axis || joypresent=(joyinp^0x0f)&0x0f; joypresent&=((joypresent&0x03)==0x03)?0x0f:0x0c; joypresent&=((joypresent&0x0c)==0x0c)?0x0f:0x03; // cerr << "Joypresent " << joypresent << "\n"; // If we have a joystick then build do a cal loop to work // out the count on a 500ms tight scanning loop // The input instruction should pretty much determine // the timout (Assuming an 8MHz std AT bus interface) ?? if(joypresent) { start=clock(); while(1) { joytimeout++; inp(GAME_PORT); if((clock()-start) > (CLOCKS_PER_SEC/2)) break; } joytimeout+=joytimeout/2; // Margin for error _disable(); outp(GAME_PORT,0); // Must set an initial zero point otherwise player is moving // until joystick cal is complete while(1) { joyinp=inp(GAME_PORT); joyinp&=0x0f; uByte mask=0x01; uLong loop,timer; // Enter scan loop, define the zero levels for each axis for(loop=0;loop<4;loop++) { if((joyinp&mask)) { joyzero[loop]++; } mask=mask<<1; } if(!(joyinp&joypresent)) break; // The everpresent timeout counter if(timer++ > joytimeout) { _enable(); Error err; err.message() << "Joystick port read has timed out."; err.description() << "The operation to read the joystick could not be completed and\n" << "Stella has aborted. Your joystick port may not be working \n" << "correctly or the joystick may have become disconnected\n"; throw(err); } } _enable(); } } ////////////////////////////////////////////////////////////////////////////// // Destructor ////////////////////////////////////////////////////////////////////////////// Terminal::~Terminal() { union _REGS regs; // I suppose we had to give the keyboard handler back someday _dos_setvect(0x09, old_key_handler); // Restore previous display mode regs.h.ah = 0x00; // Set mode command regs.h.al = default_term_mode; // Mode required int386(VGA_BIOS, ®s, ®s); ourInstanceCreated = false; } ////////////////////////////////////////////////////////////////////////////// // Update the screen with the TIA frame ////////////////////////////////////////////////////////////////////////////// void Terminal::update(TIA& tia) { uByte* currentFrame = tia.currentFrameBuffer(); uByte* previousFrame = tia.previousFrameBuffer(); uLong width = theWidth / 4; uLong height = (theHeight > 200) ? 200 : theHeight; int offset = ((200 - height) / 2) * 320; uWord* data = (uWord*)(0xa0000 + offset) + ((160 - theWidth) / 2); for(uLong y = 0; y < height; ++y) { uLong* current = (uLong*)(currentFrame + theXStart); uLong* previous = (uLong*)(previousFrame + theXStart); uWord* screen = data; for(uLong x = 0; x < width; ++x) { if(*current != *previous) { uByte* frame = (uByte*)current; *(screen++) = thePixelDataTable[*frame++]; *(screen++) = thePixelDataTable[*frame++]; *(screen++) = thePixelDataTable[*frame++]; *(screen++) = thePixelDataTable[*frame++]; } else { screen += 4; } current++; previous++; } currentFrame += 160; previousFrame += 160; data += 160; } // The old code, pre-delta days. // // unsigned char* frame = tia.frameBuffer(); // int length = tia.height() * tia.width(); // int offset = ((200 - tia.height()) / 2) * tia.width() * 2; // unsigned char* data = (unsigned char*)0xa0000 + offset; // // // for(int i = 0; i < length; ++i) // { // *(data++) = *frame; // *(data++) = *(frame++); // } // Handle any events that have occured handleEvents(); } ////////////////////////////////////////////////////////////////////////////// // Answer the state of the given event ////////////////////////////////////////////////////////////////////////////// uLong Terminal::eventState(Event event) { // If the value is not set by joystick then return the keyboard's value if(theKeyboardEventState[(int)event]) return theKeyboardEventState[(int)event]; else return theJoystickEventState[(int)event]; } ////////////////////////////////////////////////////////////////////////////// // Process any events related to the terminal ////////////////////////////////////////////////////////////////////////////// void Terminal::handleEvents() { union _REGS regs; // After call to driver // // regs.w.cx - Mouse X // regs.w.dx - Mouse Y // regs.w.bx - Mouse buttons regs.x.eax = 0x0003; int386(MOUSE_INT, ®s, ®s); theJoystickEventState[(int)Terminal::PaddleZeroPosition] = 512-regs.w.cx; theJoystickEventState[(int)Terminal::PaddleZeroFire] = (regs.w.bx & MOUSE_BUTTON_MASK)?1:0; // Joystick handling code (Aimed at the Gravis Gamepad) // GAME PORT Bit description (strictly for laughs) // // Bit 0 - JoyA X-Axis // Bit 1 - JoyA Y-Axis // Bit 2 - JoyB X-Axis // Bit 3 - JoyB Y-Axis // Bit 4 - JoyA Button 1 // Bit 5 - JoyA Button 2 // Bit 6 - JoyB Button 1 // Bit 7 - JoyB Button 2 if(joypresent) { Long timer=0,loop=0; Long counts[4]={0,0,0,0}; uByte joyinp,mask; // Handle the buttons first, they're real simple joyinp=inp(GAME_PORT); theJoystickEventState[(int)Terminal::LeftJoystickFire]=((joyinp^0xff)&0x30)?1:0; theJoystickEventState[(int)Terminal::RightJoystickFire]=((joyinp^0xff)&0xc0)?1:0; // Now do the D/A conversion _disable(); outp(GAME_PORT,0); while(1) { joyinp=inp(GAME_PORT); joyinp&=0x0f; mask=0x01; // Enter scan loop, test each axis for completion for(loop=0;loop<4;loop++) { if((joyinp&mask)) { // Conversion not complete so increment count counts[loop]++; } mask=mask<<1; } // All valid joystick latches low indicate completion of conversion if(!(joyinp&joypresent)) break; // Check for timeout and barf if we have if(timer++ > joytimeout) { _enable(); Error err; err.message() << "Joystick port read has timed out."; err.description() << "The operation to read the joystick could not be completed and\n" << "Stella has aborted. Your joystick port may not be working \n" << "correctly or the joystick may have become disconnected\n"; throw(err); } } _enable(); // do axis checking & auto calibration for(loop=0;loop<4;loop++) { if(joypresent&(1<joymax[loop]) { joymax[loop]=counts[loop]; joytrig[loop]=((joymax[loop]-joymin[loop])>>3)+16; // cerr << "Max overrun on J" << loop << " " << joymax[loop] << " " << joymin[loop] << " " << joytrig[loop] << " " << joyzero[loop] << "\n"; } if(counts[loop]>3)+16; // cerr << "Min underun on J" << loop << " " << joymax[loop] << " " << joymin[loop] << " " << joytrig[loop] << " " << joyzero[loop] << "\n"; } } } if((joypresent&0x03)) { theJoystickEventState[(int)Terminal::LeftJoystickLeft] =(counts[0] < (joyzero[0]-joytrig[0]))?1:0; theJoystickEventState[(int)Terminal::LeftJoystickRight] =(counts[0] > (joyzero[0]+joytrig[0]))?1:0; theJoystickEventState[(int)Terminal::LeftJoystickUp] =(counts[1] < (joyzero[1]-joytrig[1]))?1:0; theJoystickEventState[(int)Terminal::LeftJoystickDown] =(counts[1] > (joyzero[1]+joytrig[1]))?1:0; } if((joypresent&0x0c)) { theJoystickEventState[(int)Terminal::RightJoystickLeft] =(counts[2] < (joyzero[2]-joytrig[2]))?1:0; theJoystickEventState[(int)Terminal::RightJoystickRight]=(counts[2] > (joyzero[2]+joytrig[2]))?1:0; theJoystickEventState[(int)Terminal::RightJoystickUp] =(counts[3] < (joyzero[3]-joytrig[3]))?1:0; theJoystickEventState[(int)Terminal::RightJoystickDown] =(counts[3] > (joyzero[3]+joytrig[3]))?1:0; } } } ////////////////////////////////////////////////////////////////////////////// // // Function : kbd_int_handler() // // Author : Keith Wilkins based on code by ????? (Duh my memory) // from x2ftp.oulu.fi // // Description : This function intercepts the keyabord interrupt and // processes the interrupt. // // Accepts : nothing // // Returns : nothing // ////////////////////////////////////////////////////////////////////////////// static void __interrupt __far kbd_int_handler(void) { struct Switches { uByte scanCode; Terminal::Event eventCode; }; static Switches list[] = { { SCAN_DOWN, Terminal::LeftJoystickDown }, { SCAN_UP, Terminal::LeftJoystickUp }, { SCAN_LEFT, Terminal::LeftJoystickLeft }, { SCAN_RIGHT, Terminal::LeftJoystickRight }, // { SCAN_ENTER, Terminal::LeftJoystickFire }, { SCAN_Z, Terminal::LeftJoystickFire }, // Should be Right Control key { SCAN_ENTER, Terminal::RightJoystickFire }, { SCAN_H, Terminal::RightJoystickDown }, { SCAN_Y, Terminal::RightJoystickUp }, { SCAN_G, Terminal::RightJoystickLeft }, { SCAN_J, Terminal::RightJoystickRight }, // Should be Left Control key // { SCAN_Z, Terminal::RightJoystickFire }, { SCAN_C, Terminal::Color }, { SCAN_B, Terminal::BlackAndWhite }, { SCAN_1, Terminal::LeftDifficultyA }, { SCAN_2, Terminal::LeftDifficultyB }, { SCAN_3, Terminal::RightDifficultyA }, { SCAN_4, Terminal::RightDifficultyB }, { SCAN_S, Terminal::Select }, { SCAN_R, Terminal::Reset }, { SCAN_Q, Terminal::Quit }, }; // -=- get the scan code of the key -=- ubyte cScan_code = inp(0x60); // -=- if it is an 0xe0 or 0 then ignore it -=- if((cScan_code != 0xe0) && (cScan_code != 0)) { // Change the event state if needed for(unsigned int i = 0; i < sizeof(list) / sizeof(Switches); ++i) { if(list[i].scanCode==(cScan_code&0x7f)) { theKeyboardEventState[(int)list[i].eventCode] = ( cScan_code & 0x80 ) ? 0 : 1; } } } // -=- ack the interrupt -=- outp(0x20,0x20); }  ----------------------- Headers -------------------------------- From <@nectech.co.uk:wilki1k@nectech.co.uk> Mon Oct 14 09:26:24 1996 Return-Path: <@nectech.co.uk:wilki1k@nectech.co.uk> Received: from nectech.nectech.co.uk (nectech.nectech.co.uk [194.129.183.2]) by emin24.mail.aol.com (8.6.12/8.6.12) with SMTP id JAA09350 for ; Mon, 14 Oct 1996 09:26:20 -0400 Received: from [193.116.199.251] by nectech.nectech.co.uk id aa18895; 14 Oct 96 14:24 BST Received: from parodius by lego.nectech.co.uk (4.1/25-eef) id AA06140; Mon, 14 Oct 96 14:17:02 BST Received: by parodius with Microsoft Mail id <32624BA3@parodius>; Mon, 14 Oct 96 14:18:11 GMT From: "Wilkins, Keith" To: Chrissalo Subject: RE: Yea...! Date: Mon, 14 Oct 96 14:22:00 GMT Message-Id: <32624BA3@parodius> Encoding: 104 TEXT, 599 TEXT X-Mailer: Microsoft Mail V3.0 X-Ms-Attachment: TermDOS.cxx 17480 00-00-1980 00:00