Jump to content

Search the Community

Showing results for tags 'atari 8-bit'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Atari Systems
    • Atari General
    • Atari 2600
    • Atari 5200
    • Atari 7800
    • Atari Lynx
    • Atari Jaguar
    • Atari VCS
    • Dedicated Systems
    • Atari 8-Bit Computers
    • Atari ST/TT/Falcon Computers
  • Classic Consoles
  • Classic Computing
  • Modern Consoles
  • Gaming General
  • Marketplace
  • Community
  • Community
  • Game Programming
  • Site
  • PC Gaming
  • The Club of Clubs's Discussion
  • I Hate Sauron's Topics
  • 1088 XEL/XLD Owners and Builders's Topics
  • Atari BBS Gurus's Community Chat
  • Atari BBS Gurus's BBS Callers
  • Atari BBS Gurus's BBS SysOps
  • Atari BBS Gurus's Resources
  • Atari Lynx Programmer Club's CC65
  • Atari Lynx Programmer Club's ASM
  • Atari Lynx Programmer Club's Lynx Programming
  • Atari Lynx Programmer Club's Music/Sound
  • Atari Lynx Programmer Club's Graphics
  • The Official AtariAge Shitpost Club's Shitty meme repository
  • The Official AtariAge Shitpost Club's Read this before you enter too deep
  • Arcade Gaming's Discussion
  • Tesla's Vehicles
  • Tesla's Solar
  • Tesla's PowerWall
  • Tesla's General
  • Harmony/Melody's CDFJ
  • Harmony/Melody's DPC+
  • Harmony/Melody's BUS
  • Harmony/Melody's General
  • ZeroPage Homebrew's Discussion
  • Furry Club's Chat/RP
  • PSPMinis.com's General PSP Minis Discussion and Questions
  • PSPMinis.com's Reviews
  • Atari Lynx 30th Birthday's 30th Birthday Programming Competition Games
  • 3D Printing Club's Chat
  • Drivers' Club's Members' Vehicles
  • Drivers' Club's Drives & Events
  • Drivers' Club's Wrenching
  • Drivers' Club's Found in the Wild
  • Drivers' Club's General Discussion
  • Dirtarians's General Discussion
  • Dirtarians's Members' Rigs
  • Dirtarians's Trail Runs & Reports
  • Dirtarians's Wrenching
  • The Green Herb's Discussions
  • Robin Gravel's new blog's My blog
  • Robin Gravel's new blog's Games released
  • Atari Video Club's Harmony Games
  • Atari Video Club's The Atari Gamer
  • Atari Video Club's Video Game Summit
  • Atari Video Club's Discsuuions
  • Star Wars - The Original Trilogy's Star Wars Talk
  • PlusCart User's Bug reports
  • PlusCart User's Discussion
  • DMGD Club's Incoming!
  • DASM's General
  • AtariVox's Topics
  • Gran Turismo's Gran Turismo
  • Gran Turismo's Misc.
  • Gran Turismo's Announcements
  • The Food Club's Food
  • The Food Club's Drinks
  • The Food Club's Read me first!
  • The (Not So) Official Arcade Archives Club's Rules (READ FIRST)
  • The (Not So) Official Arcade Archives Club's Feedback
  • The (Not So) Official Arcade Archives Club's Rumor Mill
  • The (Not So) Official Arcade Archives Club's Coming Soon
  • The (Not So) Official Arcade Archives Club's General Talk
  • The (Not So) Official Arcade Archives Club's High Score Arena
  • Adelaide South Australia Atari Chat's General Chat & Welcome
  • Adelaide South Australia Atari Chat's Meets
  • Adelaide South Australia Atari Chat's Trades & Swaps
  • KC-ACE Reboot's KC-ACE Reboot Forum
  • The Official Lost Gaming Club's Lost Gaming
  • The Official Lost Gaming Club's Undumped Games
  • The Official Lost Gaming Club's Tip Of My Tounge
  • The Official Lost Gaming Club's Lost Gaming Vault
  • The Official Lost Gaming Club's Club Info
  • GIMP Users's Discussion

Blogs

There are no results to display.

There are no results to display.

Calendars

  • AtariAge Calendar
  • The Club of Clubs's Events
  • Atari BBS Gurus's Calendar

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website


Facebook


Twitter


Instagram


YouTube


eBay


GitHub


Custom Status


Location


Interests


Currently Playing


Playing Next

Found 42 results

  1. UPDATE - Problem seems to be solved, current game date is October 5, 1941, on intermediate skill. Solution seems to be playing on higher skill level. Hello! Brand new to the site, please forgive my mistakes at this tender age. For my first post, I have a question about a game. Eastern Front 1941, on an Atari 800 with 48k RAM. Running on real hardware, no emulation. I'm currently playing and am becoming increasingly frustrated by the fact that I cannot get passed turn 14. I have read through the manual several times and researched on the internet for the passed 3 days. I do understand the mechanics of moving, attacking, supply, etc enough that I can push the russians around pretty well, but no matter what I do I invariably get a Game Over on September 28th game time, or turn 14. I'm testing out the different difficulty levels as I am typing this post, on intermediate right now, but I expect the same result. All sources say the game runs for 41 turns, and ends on March 29, 1942. What is wrong? Is my cartidge damaged? Is there something about the game that the manual isn't telling me? Is my computer broken? Thanks for any helpful input!
  2. Convert Integer To Bit String ============================================================== Part 1 - Introduction http://atariage.com/forums/blog/576/entry-13175-part-1-of-11-simple-assembly-for-atari-basic/ Part 2 - Learn 82.7% of Assembly Language in About Three Pages http://atariage.com/forums/blog/576/entry-13176-part-2-of-11-simple-assembly-for-atari-basic/ Part 3 - The World Inside a USR() Routine http://atariage.com/forums/blog/576/entry-13177-part-3-of-11-simple-assembly-for-atari-basic/ Part 4 - Implement DPEEK() http://atariage.com/forums/blog/576/entry-13178-part-4-of-11-simple-assembly-for-atari-basic/ Part 5 - Implement DPOKE http://atariage.com/forums/blog/576/entry-13180-part-5-of-11-simple-assembly-for-atari-basic/ Part 6 - Various Bit Manipulations http://atariage.com/forums/blog/576/entry-13181-part-6-of-11-simple-assembly-for-atari-basic/ Part 7 - Convert Integer to Hex String http://atariage.com/forums/blog/576/entry-13182-part-7-of-11-simple-assembly-for-atari-basic/ Part 8 - Convert Integer to Bit String http://atariage.com/forums/blog/576/entry-13183-part-8-of-11-simple-assembly-for-atari-basic/ Part 9 - Memory Copy http://atariage.com/forums/blog/576/entry-13184-part-9-of-11-simple-assembly-for-atari-basic/ Part 10 - Binary File I/O Part 1 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13185-part-10-of-11-simple-assembly-for-atari-basic/ Part 11 - Binary File I/O Part 2 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13186-part-11-simple-assembly-for-atari-basic-the-end/ ============================================================== This machine language routine converts a 16-bit integer into a string of values representing 0 and 1 bits. This is useful for visualizing bits in a byte, word, or address for diagnostic purposes. This is practical on the Atari for displaying character set or player/missile graphics data in a human-readable way. This routine has a different number of arguments from the INT2HEX string conversion routine and so is presented on its own. This routine has similar problems to solve as the INT2HEX routine. It must deal with the low byte stored in memory before the high byte, because it must output the bit values in order of highest bits first and lowest bits last. (e.g 258 or hex $0102 should be output as “0000000100000010” though it is stored as $02 $01). Converting a byte to a string of bits is fairly easy in 6502. In general terms: test the high bit and output a “0” or a “1” as needed, then shift the bits of the byte and repeat until 8 bits have been extracted. The routine below includes a touch of customization – the USR() routine may also specify the characters (ASCII/ATASCII) used to represent “0” and “1”. INT2BITS in Mac/65 Assembler Code 0100 ; INT2BITS 0105 ; 0110 ; Convert 16-bit integer into 0115 ; string of bits. 0120 ; 0125 ; INT2BITS USR 2 arguments: 0130 ; Value == Integer to convert. 0135 ; StrAdr == Address of string 0140 ; which must be able 0145 ; to hold 16 characters 0150 ; Zero == Character used for 0155 ; clear bit. 0160 ; One == Character used for 0165 ; set bit. 0170 ; 0175 ; USR return value 0 means no 0180 ; conversion. Non-Zero means 0185 ; STRADR contains data. 0190 ; 0195 ; Use the FR0/FR1 FP register. 0200 ; The return value for BASIC 0205 ; goes in FR0. 0210 ; No FP is used so all of FR0 0215 ; (and more FP registers) can 0220 ; be considered available. 0225 ; 0230 ZRET = $D4 ; FR0 $D4/$D5 Return value 0235 ZARGS = $D5 ; $D6-1 for arg Pulldown loop 0240 ZONE = $D6 ; FR0 $D6/$D7 char for "1" 0245 ZZERO = $D8 ; FR0 $D8/$D9 char for "0" 0250 ZSTR = $DA ; FR0 $DA/$DB StrAdr 0255 ZVAL = $DC ; FR0 $DC/$DD Integer value 0260 ; 0265 .OPT OBJ 0270 ; 0275 ; Arbitrary. This is relocatable. 0280 ; 0285 *= $9300 0290 ; 0295 INIT 0300 LDA #$00 ; Make sure return 0305 STA ZRET ; value is cleared 0310 STA ZRET+1 ; by default. 0315 PLA ; Get argument count 0320 BEQ EXIT ; Shortcut for no args 0325 ASL A ; Now number of bytes 0330 TAY 0335 CMP #$08 ; Integer Value1, StrAdr, Zero, One 0340 BEQ PULLDOW N0345 ; 0350 ; Bad args. Clean up for exit. 0355 ; 0360 DISPOSE ; any number of args 0365 PLA 0370 DEY 0375 BNE DISPOSE 0380 RTS ; Abandon ship 0385 ; 0390 ; This code works the same 0395 ; for 1, 4, 8 ... arguments. 0400 ; 0405 PULLDOWN 0410 PLA 0415 STA ZARGS,Y 0420 DEY 0425 BNE PULLDOWN 0430 ; 0435 ; Arg validation. 0440 ; StrAdr may not be null. 0445 ; Zero and One may not 0450 ; be equal. 0455 ; 0460 LDA ZSTR 0465 ORA ZSTR+1 0470 BEQ EXIT ; zstr is null 0475 LDA ZZERO 0480 CMP ZONE 0485 BEQ EXIT ; zero == one 0490 ; 0495 ; Break Integer Value into 0500 ; bytes and test bits from 0505 ; high to low... 0510 ; 0515 LDX #$01 ; X index bytes. 0520 ; Y is already 0 0525 ; Y index string. 0530 ; 0535 WALK_BITS 0540 CLC 0545 ASL ZVAL,X ; Shift out bit 0550 LDA ZZERO ; Assume Zero 0555 BCC COPY2STR ; Copy if so 0560 LDA ZONE ; Actually One 0565 COPY2STR 0570 STA (ZSTR),Y 0575 INY ; Next string position 0580 CPY #$08 ; End of high byte? 0585 BEQ NEXT_BYTE ; Yes. Dec index. 0590 CPY #$10 ; End of low byte? 0595 BNE WALK_BITS ; No, loop again. 0600 NEXT_BYTE 0605 DEX ; 1, 0 will continue 0610 BPL WALK_BITS ; -1 ends loop 0615 END_LOOP 0620 ; 0625 INC ZRET ; Successful return 0630 EXIT 0635 RTS 0640 ; 0645 .END The variable validation has a trivial addition to make sure the character values for “0” and “1” are not the same: 0475 LDA ZZERO 0480 CMP ZONE 0485 BEQ EXIT ; zero == one Unlike the hex conversion there is just one part to the bit conversion: 0515 LDX #$01 ; X index bytes. 0520 ; Y is already 0 0525 ; Y index string. 0530 ; 0535 WALK_BITS 0540 CLC 0545 ASL ZVAL,X ; Shift out bit 0550 LDA ZZERO ; Assume Zero 0555 BCC COPY2STR ; Copy if so 0560 LDA ZONE ; Actually One 0565 COPY2STR 0570 STA (ZSTR),Y 0575 INY ; Next string position 0580 CPY #$08 ; End of high byte? 0585 BEQ NEXT_BYTE ; Yes. Dec index. 0590 CPY #$10 ; End of low byte? 0595 BNE WALK_BITS ; No, loop again. 0600 NEXT_BYTE 0605 DEX ; 1, 0 will continue 0610 BPL WALK_BITS ; -1 ends loop 0615 END_LOOP There are two loops happening here. One loop, indexed by X, counts in reverse, 1 to 0, from the high byte to the low byte of the integer. Within that loop is the activity to output all the bits in the byte which is done as part of the loop indexed by Y to count from character position 0 to 15. When the Y loop reaches values 8 and 16 it signals that all the bits in the byte have been output, so then it is time to continue the outer loop to get the next byte. The Y index is thus incremented 8 times for each decrement (one byte) of the X loop. As with the integer to hexadecimal conversion this utility receives the address of the output string, not its control information, so it can only fill in the bytes in the string and can't change the size as BASIC understands it. A BASIC program using the results of the conversion must insure that it populates the length of the string prior to calling the conversion utility: 10 DIM A$(16) 20 A$=" ":REM 16 SPACES Now that we have routines to convert values into hex strings and bit representation, the test program for BITS can be revisited to provide improved diagnostic information. Testing BITS Again (with INT2HEX and INT2BITS) Below is the Atari BASIC TESTBITS.BAS program upgraded with the new conversion utilities to produce much more sensible output illustrating the changes in the bits: 100 REM TESTBIT2.BAS 105 REM TEST BIT OPERATIONS UTILITY 2 110 GRAPHICS 0:POKE 710,0:POKE 82,0 115 DIM B(3,1),N$(21),HX$(5),BIT$(17) 120 N$="OR ANDEORLSRLSLRORROL" 125 HX$=" ":BIT$=" " 130 AZERO=48:AONE=49:REM ATASCII 0 1 135 REM ENUMERATE BIT OPERATIONS 140 RESTORE 150 145 READ BOR,BAND,BEOR,BLSR,BLSL,BROR,BROL 150 DATA 1,2,3,4,5,6,7 155 GOSUB 10000:REM BITS UTILITY 160 RESTORE 190:REM BIT PATTERNS 165 FOR X=0 TO 1 170 FOR Y=0 TO 3 175 READ D:B(Y,X)=D 180 NEXT Y 185 NEXT X 190 DATA 0,257,0,257,0,0,258,258 195 REM 200 REM TEST OR, AND, EOR 205 REM 210 FOR OPER=BOR TO BEOR 215 FOR Y=0 TO 3 220 ? " "; 225 VALUE=B(Y,0):GOSUB 405 230 ? N$(OPER*3-2,OPER*3); 235 VALUE=B(Y,1):GOSUB 405 240 ? "=== ===== ===================" 245 VALUE=USR(BITS,OPER,B(Y,0),B(Y,1)) 250 ? " ";:GOSUB 405 255 ? 260 NEXT Y 265 NEXT OPER 270 REM 275 REM TEST SHIFT AND ROTATE 280 REM 285 V=129:REM $81 290 FOR OPER=BLSR TO BROL 295 ? "Testing ";N$(OPER*3-2,OPER*3);" on Value "; 300 VALUE=V:GOSUB 505 305 FOR Y=0 TO 8 310 ? N$(OPER*3-2,OPER*3);" ";Y;" = "; 315 VALUE=USR(BITS,OPER,V,Y) 320 GOSUB 505 325 NEXT Y 330 ? 335 NEXT OPER 340 END 400 REM 401 REM OUTPUT INTEGER CONVERTED TO 402 REM USEFUL FORMAT: 403 REM $HEX = BITS BITS BITS BITS 404 REM 405 RH=USR(INT2HEX,VALUE,ADR(HX$)) 406 RB=USR(BIT2STR,VALUE,ADR(BIT$),AZERO,AONE) 407 ? " $";HX$;" = ";BIT$(1,4);" ";BIT$(5,;" ";BIT$(9,12);" ";BIT$(13,16) 408 RETURN 500 REM 501 REM OUTPUT BYTE VALUE CONVERTED TO 502 REM USEFUL FORMAT: 503 REM $HEX = BITS BITS 504 REM 505 RH=USR(INT2HEX,VALUE,ADR(HX$)) 506 RB=USR(BIT2STR,VALUE,ADR(BIT$),AZERO,AONE) 507 ? "$";HX$(3,4);" = ";BIT$(9,12);" ";BIT$(13,16) 508 RETURN 9997 REM 9998 REM SETUP ML UTILITIES 9999 REM 10000 DIM BT$(162),B2S$(67),I2H$(72) 10001 BITS=ADR(BT$) 10002 RESTORE 27000:? "Loading BITS" 10003 FOR I=0 TO 161 10004 READ D:POKE BITS+I,D 10005 NEXT I:? 10006 BIT2STR=ADR(B2S$) 10007 RESTORE 25000:? "Loading BIT2STR" 10008 FOR I=0 TO 66 10009 READ D:POKE BIT2STR+I,D 10010 NEXT I:? 10011 INT2HEX=ADR(I2H$) 10012 RESTORE 26000:? "Loading INT2HEX" 10013 FOR I=0 TO 71 10014 READ D:POKE INT2HEX+I,D 10015 NEXT I:? 10016 RETURN 24996 REM H1:INT2BITS.OBJ 24997 REM SIZE = 67 24998 REM START = 37632 24999 REM END = 37698 25000 DATA 169,0,133,212,133,213,104,240 25001 DATA 57,10,168,201,8,240,5,104 25002 DATA 136,208,252,96,104,153,213,0 25003 DATA 136,208,249,165,218,5,219,240 25004 DATA 33,165,216,197,214,240,27,162 25005 DATA 1,24,22,220,165,216,144,2 25006 DATA 165,214,145,218,200,192,8,240 25007 DATA 4,192,16,208,236,202,16,233 25008 DATA 230,212,96 25996 REM H1:INT2HEX.OBJ 25997 REM SIZE = 72 25998 REM START = 37888 25999 REM END = 37959 26000 DATA 169,0,133,212,133,213,104,240 26001 DATA 62,10,168,201,4,240,5,104 26002 DATA 136,208,252,96,104,153,213,0 26003 DATA 136,208,249,5,215,240,40,216 26004 DATA 162,1,181,216,74,74,74,74 26005 DATA 145,214,181,216,41,15,200,145 26006 DATA 214,200,202,16,237,136,177,214 26007 DATA 201,10,144,2,105,6,105,48 26008 DATA 145,214,136,16,241,230,212,96 26996 REM H1:BITS.OBJ 26997 REM SIZE = 162 26998 REM START = 38144 26999 REM END = 38305 27000 DATA 169,0,133,212,133,213,104,240 27001 DATA 43,10,168,201,6,240,5,104 27002 DATA 136,208,252,96,104,153,213,0 27003 DATA 136,208,249,164,218,240,21,136 27004 DATA 240,19,136,240,29,136,240,39 27005 DATA 136,240,49,136,240,61,136, 27006 DATA 73,136,240,90,96,165,216,5 27007 DATA 214,133,212,165,217,5,215,133 27008 DATA 213,96,165,216,37,214,133,212 27009 DATA 165,217,37,215,133,213,96,165 27010 DATA 216,69,214,133,212,165,217,69 27011 DATA 215,133,213,96,165,216,133,212 27012 DATA 166,214,240,208,74,202,208,252 27013 DATA 133,212,96,165,216,133,212,166 27014 DATA 214,240,193,10,202,208,252,133 27015 DATA 212,96,165,216,133,212,166,214 27016 DATA 240,178,24,106,144,2,9,128 27017 DATA 202,208,247,133,212,96,165,216 27018 DATA 133,212,166,214,240,158,24,42 27019 DATA 144,2,9,1,202,208,247,133 27020 DATA 212,96 Here is the kinder, gentler TESTBIT2 output with the values and bits illustrated: Loading BITS Loading BIT2STR Loading INT2HEX $0000 = 0000 0000 0000 0000 OR $0000 = 0000 0000 0000 0000 === ===== =================== $0000 = 0000 0000 0000 0000 $0101 = 0000 0001 0000 0001 OR $0000 = 0000 0000 0000 0000 === ===== =================== $0101 = 0000 0001 0000 0001 $0000 = 0000 0000 0000 0000 OR $0102 = 0000 0001 0000 0010 === ===== =================== $0102 = 0000 0001 0000 0010 $0101 = 0000 0001 0000 0001 OR $0102 = 0000 0001 0000 0010 === ===== =================== $0103 = 0000 0001 0000 0011 $0000 = 0000 0000 0000 0000 AND $0000 = 0000 0000 0000 0000 === ===== =================== $0000 = 0000 0000 0000 0000 $0101 = 0000 0001 0000 0001 AND $0000 = 0000 0000 0000 0000 === ===== =================== $0000 = 0000 0000 0000 0000 $0000 = 0000 0000 0000 0000 AND $0102 = 0000 0001 0000 0010 === ===== =================== $0000 = 0000 0000 0000 0000 $0101 = 0000 0001 0000 0001 AND $0102 = 0000 0001 0000 0010 === ===== =================== $0100 = 0000 0001 0000 0000 $0000 = 0000 0000 0000 0000 EOR $0000 = 0000 0000 0000 0000 === ===== =================== $0000 = 0000 0000 0000 0000 $0101 = 0000 0001 0000 0001 EOR $0000 = 0000 0000 0000 0000 === ===== =================== $0101 = 0000 0001 0000 0001 $0000 = 0000 0000 0000 0000 EOR $0102 = 0000 0001 0000 0010 === ===== =================== $0102 = 0000 0001 0000 0010 $0101 = 0000 0001 0000 0001 EOR $0102 = 0000 0001 0000 0010 === ===== =================== $0003 = 0000 0000 0000 0011 Testing LSR on Value $81 = 1000 0001 LSR 0 = $81 = 1000 0001 LSR 1 = $40 = 0100 0000 LSR 2 = $20 = 0010 0000 LSR 3 = $10 = 0001 0000 LSR 4 = $08 = 0000 1000 LSR 5 = $04 = 0000 0100 LSR 6 = $02 = 0000 0010 LSR 7 = $01 = 0000 0001 LSR 8 = $00 = 0000 0000 Testing LSL on Value $81 = 1000 0001 LSL 0 = $81 = 1000 0001 LSL 1 = $02 = 0000 0010 LSL 2 = $04 = 0000 0100 LSL 3 = $08 = 0000 1000 LSL 4 = $10 = 0001 0000 LSL 5 = $20 = 0010 0000 LSL 6 = $40 = 0100 0000 LSL 7 = $80 = 1000 0000 LSL 8 = $00 = 0000 0000 Testing ROR on Value $81 = 1000 0001 ROR 0 = $81 = 1000 0001 ROR 1 = $C0 = 1100 0000 ROR 2 = $60 = 0110 0000 ROR 3 = $30 = 0011 0000 ROR 4 = $18 = 0001 1000 ROR 5 = $0C = 0000 1100 ROR 6 = $06 = 0000 0110 ROR 7 = $03 = 0000 0011 ROR 8 = $81 = 1000 0001 Testing ROL on Value $81 = 1000 0001 ROL 0 = $81 = 1000 0001 ROL 1 = $03 = 0000 0011 ROL 2 = $06 = 0000 0110 ROL 3 = $0C = 0000 1100 ROL 4 = $18 = 0001 1000 ROL 5 = $30 = 0011 0000 ROL 6 = $60 = 0110 0000 ROL 7 = $C0 = 1100 0000 ROL 8 = $81 = 1000 0001 The output is considerably easier to understand. So neat, so organized, so obvious and informative! Below are the source files and examples of how to load the machine language routine into BASIC included in the disk image and archive: INT2BITS File List: INT2BITS.M65 Saved Mac/65 source INT2BITS.L65 Mac/65 source listing INT2BITS.T65 Mac/65 source listed to H6: (linux) INT2BITS.ASM Mac/65 assembly listing INT2BITS.TSM Mac/65 assembly listing to H6: (linux) INT2BITS.OBJ Mac/65 assembled machine language program (with load segments) INT2BITS.BIN Assembled machine language program without load segments INT2BITS.LIS LISTed DATA statements for INT2BITS.BIN routine. INT2BITS.TLS LISTed DATA statements for INT2BITS.BIN routine to H6: (linux) MAKEI2B.BAS BASIC program to create the INT2BITS.BIN file. This also contains the INT2BITS routine in DATA statements. MAKEI2B.LIS LISTed version of MAKEI2B.BAS MAKEI2B.TLS LISTed version of MAKEI2B.BAS to H6: (linux) TESTI2B.BAS BASIC program that tests the INT2BITS USR() routines. TESTI2B.LIS LISTed version of TESTI2B.BAS. TESTI2B.TLS LISTed version of TESTI2B.BAS to H6: (linux) ZIP archive of files: Convert_Disk.zip Tar archive of files (remove the .zip after download) Convert_Disk.tgz.zip The Lord will fulfill his purpose for me; your steadfast love, O Lord, endures forever. Do not forsake the work of your hands. Psalm 138:8
  3. A short time ago I found some (debatably) useful utilities for the Atari 8-bit while scraping a crate of old floppies into ATR files. One of these is a character set editor I have been working on (and off) for a few decades. I spent most of July adding a few useful features for the modern era of Atari emulators, and dealing with some bugs. So, here's a new toy to play with, GRID EDIT. The attached ZIP file will unpack to an ATR. I ordinarily use this as D2:. GRIDEDIT_ATR.zip Better docs should be completed soon, (Copy and paste from a word doc is not looking very good.) Here's a first stab at useful info... ==================================================== REQUIRES 40K RAM, OSS BASIC XL, floppy disk drive or emulator supporting Host drives. PROBABLY REQUIRES DOS 2.0S, or other DOS with an equally small (or smaller) footprint. With DOS2.0S there is about 1.4K of free ram between the end of the program, and the fixed location of the first character set in RAM. RECOMMENDED Joystick, or Touch Tablet FEATURES Edits 8 fonts in memory. Most functions/operations can be applied to a single character or an entire font. Reverts font changes to the last saved version, the version read at startup, or the original ROM version. An onscreen doodling area allowing preview of the fonts with font and color changes permitted per line. Keyboard, Joystick, or Touch Tablet operation. Non-modal (mostly) input methods allow open workflow for the user. (Simultaneous editing, menu, and doodling operations.) ==================================================== INTRODUCTION My favorite Atari 8-bit feature is redefined character sets, because it is fairly simple to utilize and so readily fit into my tiny brain. Atari’s character set magic provides considerable bang for the buck allowing even slow BASIC programs to achieve graphics movement approximating animation. Over the years I’ve collected and written countless character set editors. GRIDEDIT is one of my old, much-abused BASIC prototypes of unpolished features and experimental user interfaces hacked up prior to writing better versions in Assembly. This is a simple character editor for ANTIC Mode 2 (GRAPHICS 0) text fonts. It can also be applied to Mode 6/7 text with the understanding the program does not show colored characters. GRIDEDIT was originally developed using the Atari 800 with 48K (and cassette!). A few changes were recently added using Altirra emulating a 64K 800XL. Seems to work fine. ==================================================== SUMMARY In the upper left is the edit grid to change the current character. in the top center of the screen is the menu to choose actions, switch fonts, etc. In the upper right is the character selector showing all 128 Atari font characters. Below the selector is a status line reporting the state/behavior of the program. In the center of the screen is a preview line that shows the current font centered on the current character being edited. At the bottom of the screen is a doodling area. Each row of text can have its own colors and fonts assigned. (DLI abuse going on.) The user’s input cursor appears as a flashing block on the screen. Move the cursor with the current input device – the arrow keys, the joystick, or the touch tablet stylus. Press a controller button or use the Space Bar or Enter key to select the item under the cursor. The display/user input is primarily non-modal. While a Menu is waiting for input the Edit Grid is still functional, the Character Selector can choose characters in the current font, and the Doodling area allows drawing characters. ==================================================== EDIT GRID The Edit Grid presents an 8 x 8 grid of the current character's bitmap. Within the bitmap the controller button(s) (or keyboard) turn bits on and off: Use the joystick button to toggle bits on and off. Use the keyboard’s ‘Return’ and ‘/’ keys to turn bits on and off. Use the touch tablet’s left, right, and stylus buttons to turn bits on and off. The outer borders are shortcuts for bit shifting operations. Selecting the outermost border containing arrows will move the entire bitmap contents in the direction of the arrow. The next border inside will move just the bits in that horizontal line or vertical column. The ‘S’ or ‘R’ characters at the corners of the inner border indicate the current bit shifting mode when selecting the bit shift shortcut borders. The character displayed in inverse video indicates which mode is in effect: S – “SHIFT”: bits shifted past the borders of the grid are lost, and the new bits shifted in are zero/clear. R – “ROLL” bits shifted past the borders of the grid “roll” around and reappear as the new bits on the opposite side of the grid. ==================================================== MENU The menu allows choice of functions or operations. A choice is made by moving the cursor to the corresponding line and pressing the controller button or Return key. Some choices will present other menus. Most menus have a Cancel option as the last entry that will quit the current line of prompting and return to an earlier menu. Some Menus include an OK option to accept the changes made on screen. ==================================================== CHARACTER SELECTOR This array presents all 128 Atari characters. Move the cursor to the desired character and press the controller button or Return key to edit the character in the current font. ==================================================== STATUS The status box provides important information to the user. The first line reports the current Font (1 to 8 ) and the character being edited as a hexadecimal value for its position in the font. The left half of the second line displays the list of possible input devices. The current input device is shown as an abbreviation – “Joy” for joystick, “Key” for keyboard, and “Tab” for Atari touch tablet. The input devices not in use are represented by a single inverse video character of the key to press to activate the device. (‘J’, ‘K’, or ‘T’). The right half of the second line displays the current mode for bit manipulation functions and other operations. The values may be “Char” or “All”. “Char” mode means the function or operation chosen works only on the current character. In “All” mode the functions and operations act on the entire current font. The first character of each mode appears as inverse video indicating the key to press to set the mode. The last line of status displays the font and character information marked as the intended source for the Copy operation. The first value is the font number, then a slash, then the hexadecimal value of the character’s position in the font. ==================================================== PREVIEW The Preview lines show the current font on the top line, and inverse video on the second line. A flashing marker appears above and below the current character. Additionally, the Preview display also allows choosing the character to edit. Move the cursor to the desired character and press the controller button or Return key to edit the character in the current font. ==================================================== DOODLING The Doodling area allows plotting the current character in a 40 character x 8 line display. Each line of the display can be adjusted to set a new value for font (CHBASE), character control (CHACTL), Border color (COLBK), line color (COLPF2) and text luminance (COLPF1). The joystick button plots the character on screen. The ‘Return’ key also plots, and the ‘/’ key plots the inverse video value of the current character. Likewise, the touch tablet buttons plot in normal and inverse video. ==================================================== STARTUP LOAD the program into OSS BASIC XL, and RUN it. After a few moments the program will present a list of disk drive devices choices numbered 1 through 4. Choose the disk device to use as the default device by pressing the corresponding number key. The Return key is not needed. The chosen default device will be used for all subsequent save and load operations. The program will attempt to load eight fonts from the default disk drive. The fonts have fixed names on the disk: FONT1.FNT, FONT2.FNT, etc. up to FONT8.FNT. If a file is not found then the program will automatically use a copy of the internal ROM font. The program will save a backup file on the default disk device for each font. The backup for FONT1.FNT is F1.FNT, FONT2.FNT is F2.FNT, and so on. The backup is created only during the program startup and never written again. If the DOODLE.DAT file exists, the program will load the configuration of the Doodling area from that file including the characters that had been drawn in the Doodle area, and the fonts and colors chosen for each of the lines. ==================================================== INPUT The cursor may be controlled and input provided via keyboard, joystick, or touch tablet. Special keys controlling the operating configuration function regardless of the current input method. KEYBOARD Use the arrow keys (with or without the ctrl key) to move the cursor. JOYSTICK Use the joystick plugged into the first joystick port to move the cursor. The joystick button will choose items, draw pixels in the current character, or draw in the doodle are depending on the location of the cursor. TOUCH TABLET The tablet stylus will move the cursor around the screen. CONFIGURATION KEYS Configuration keys are always available regardless of the type of input. K - Set keyboard input J – Set joystick input T – Set touch tablet input C - Set Character-only mode for Functions A - Set All (entire Font) mode for Functions S - Set Bit Shift mode for Grid Editor R - Set Bit Roll mode for Grid Editor ==================================================== BUGS There are certainly more than enough bugs to go around. Share with friends and enjoy. You’re welcome. “All” mode has side effects when editing a Doodle row’s configuration: When a Doodle configuration item menu is entered (CHBASE, COLBK, etc.), the program automatically changes all the lines’ values to the current value for the chosen line. Since only the last value of the current row is remembered for the case of the Cancel menu choice, it causes Cancel to return all the rows to the previous value of the current row, not the previous value of each individual row. Switching back to “Char” mode will cause the Cancel menu item to revert only the chosen Doodle row’s configuration, leaving all the other rows modified. ==================================================== RANDOM NOTES Disregard that FRE(0) says there’s about 10.5K of free memory. The 8 fonts are at fixed locations starting at $7800. This works out to about 1.4K of actual free memory. The lowest hanging fruit for optimizing has been done – using variables in place of constants. Without that the program would probably be looking at space for only 5 fonts. This program had little pre-planning - - or 30 years of design consideration depending on the point of view. It has been hacked on over and over to add features and change behaviors. Due to this there are redundant variables and temporary variables that occur only once in the code. Finding and optimizing this is an exercise for the masochistic. The easiest way to free up a ton of memory is to remove the many, many REMark lines. That is, if you never intend to understand the program. Reading comprehension plummets without the comments. Those who understand Display List Interrupts will recognize that the DLIs for the Doodling area are doing three and one-half things more than can actually fit in the horizontal blank time allowed. It is what it is. The DLIs are there just to provide a rough guess of what the characters sets will look like. The most recent round of hacks made the program play nicer with an emulator (Altirra preferred for Windows). This added support for Host drives (really trivial) and touch tablet input. An emulator implementing a fake touch tablet is a cheap way to have mouse support from the Host environment without handling the mouse in the Atari itself and so frees the Atari from the overhead of a polling (or frequently interrupting) machine language handler. Tablet support took just about an hour to work out tablet coordinates vs the Player/Missile screen cursor. ==================================================== WHY OSS BASIC XL? I work in straight Atari BASIC only if someone requires it. OSS BASIC XL is 99% of my BASIC use and one of the underappreciated gems on the Atari 8-bits. It bugged me that Atari magazines back in the day printed articles for Action!, but never for BASIC XL which had a much larger user base. It loads Atari BASIC tokenized (SAVE’d) programs without changes, 99% compatible ENTER’ing programs previously LIST’ed by Atari BASIC. It is faster (much faster) than Atari BASIC. BASIC XL provides a heap of neat, built-in extra features… Player/Missile graphics support. Memory move at machine language speeds. String arrays. Structured statements: If/Else/Endif and While/Endwhile FAST mode that predetermines line location to eliminate the line lookup overhead. [*]It fits in a ROM cart occupying the same memory as 8K Atari BASIC. [*]Everyone and their cousin should be able to easily get the ROM running under emulation.
  4. pmgraphics

    chiseler 43277

    From the album: Chiseler

    Atari computer classic type-in-code video game. Breaking 40K on Chiseler. Youtube link to video since album doesn't seem to takevideos.
  5. From the album: Chiseler

    Atari computer classic type-in-code video game. Youtube link to video since album doesn't seem to take videos.
  6. Hello! I want to share some ATARI POKEY I made. These are both originals and covers, along with some behind the scenes. So, without further ado, I'm going to leaving this link here: https://www.youtube.com/watch?v=jgwcI3ATf3U&list=PLptR0gr8Js-44DoEDc_ZvYY6wlQWZZbcC Please, enjoy! I'm also looking forward to hearing from you all!
  7. Looking for a replacement top and bottom shell for my 1979 style Atari 800. If anyone has one, or a parts unit I could pull the shell off of, let me know. I'm open to negotiating on price. Thanks!
  8. At the Personal Computer Museum we have recently acquired a second copy of the reasonably rare Inhome Software "Baseball". Here are pictures I took yesterday showing the cart working on one of our Atari 800's ... you can also see the condition of the label (definitely not perfect) - but hey it's rare and it works! I would PREFER to trade it with another community member who will appreciate it and can help build our collection. You can see which Atari 8-bit items we currently have at our website (the link for Atari 8-bit is http://www.pcmuseum....oup=Atari 8-bit) - although of course I would even consider trading for other Atari items as well (or anything retro computing really). We are located in Canada so keep that in mind for shipping purposes. Of course, I would sell it as well but like I said a trade I think would work better. Let me know! thanks
  9. Hi Guys, Haven't posted here in ages, but thought some of you may be interested in checking out my Tumblr blog with animated GIFs of retro games. I have a large section of animated Atari 8-bit screenshots under: http://286ega.tumblr.com/tagged/atari
  10. Binary File I/O (Part 1 of 2) ============================================================== Part 1 - Introduction http://atariage.com/forums/blog/576/entry-13175-part-1-of-11-simple-assembly-for-atari-basic/ Part 2 - Learn 82.7% of Assembly Language in About Three Pages http://atariage.com/forums/blog/576/entry-13176-part-2-of-11-simple-assembly-for-atari-basic/ Part 3 - The World Inside a USR() Routine http://atariage.com/forums/blog/576/entry-13177-part-3-of-11-simple-assembly-for-atari-basic/ Part 4 - Implement DPEEK() http://atariage.com/forums/blog/576/entry-13178-part-4-of-11-simple-assembly-for-atari-basic/ Part 5 - Implement DPOKE http://atariage.com/forums/blog/576/entry-13180-part-5-of-11-simple-assembly-for-atari-basic/ Part 6 - Various Bit Manipulations http://atariage.com/forums/blog/576/entry-13181-part-6-of-11-simple-assembly-for-atari-basic/ Part 7 - Convert Integer to Hex String http://atariage.com/forums/blog/576/entry-13182-part-7-of-11-simple-assembly-for-atari-basic/ Part 8 - Convert Integer to Bit String http://atariage.com/forums/blog/576/entry-13183-part-8-of-11-simple-assembly-for-atari-basic/ Part 9 - Memory Copy http://atariage.com/forums/blog/576/entry-13184-part-9-of-11-simple-assembly-for-atari-basic/ Part 10 - Binary File I/O Part 1 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13185-part-10-of-11-simple-assembly-for-atari-basic/ Part 11 - Binary File I/O Part 2 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13186-part-11-simple-assembly-for-atari-basic-the-end/ ============================================================== Sidebar: This section turned out to be considerably more difficult and time consuming to write than anticipated. No two sources agree completely on this subject. The only consistency I found is the list of CIO and XIO command numbers. Everything else encountered documents this subject with varying amounts of accuracy. Descriptions of the CIO and XIO commands sometimes differ in the just names, but in ways that imply different expectations for results. Detailed descriptions of the commands vary from the strangely incomplete to being outright wrong. One guide for machine language on this subject described CIO features using the BASIC XIO limitations. Another tutorial declared that only 155 bytes could be read in one operation. In the end it took writing test programs in BASIC and Assembly to understand precisely how XIO commands work vs how the corresponding CIO commands actually do work. If anyone cares, the stuff that worked is derived from reading De Re Atari (50%, which was mostly correct), Compute!'s Mapping the Atari (20% and it has a couple mistakes), Atari's BASIC Reference Manual (15% which was painful and incomplete), and rest from several 6502 programming manuals that were altogether horriffic. Stating that programs work with data would be borderline silly. Everything about programs is about working with data – they calculate data, manipulate data, and copy data. A fundamental concern of programming is how to introduce data to the program and get it back out. Many programs have their data built into them or receive data by computing values, reading from storage, or by other input/output device or communications. A file contains data. A serial port sends and receives data. A joystick provides data. Numbers are data, text is data, graphic information is data. Data, Data, Data. Atari BASIC programs have access to several data acquisition methods. Data may be stored in a program using DATA statements. Data may be read from a file, or from user input. Although all data is ultimately represented as bytes in memory, BASIC languages provide a higher abstraction where the data it accepts is usually expressed as text and numbers, and even in the case of number values the input and output data is expressed as the text equivalent of the number value. This means data presented to BASIC is typically not in its final, usable form for the computer. The BASIC language reads the text data then converts it into a format the computer understands. Although an Atari BASIC program can contain its own data, it cannot have the data built into it in a form that is immediately usable. For instance, variables and array elements must be specifically initialized. The program must assign the values as it runs. There is not even a default behavior to clear numeric array values to zero. Data contained in DATA statements is not immediately usable by the Atari's unique features. The Atari's custom hardware features often use blocks of binary data – Graphics data, character set data, Player/Missile images, etc. The Atari BASIC DATA statement cannot present arbitrary binary data. It can only present decimal numbers and strings with limitations on the characters that can be included in the string. Like most BASIC languages, Atari BASIC has little provision for dealing with data in the computer's terms other than PEEK and POKE. Most Atari BASIC programs creating data in memory for Atari graphics features will read DATA statements – the text equivalent of number values – and then POKE those values as bytes into memory. This consumes a lot of storage space in the BASIC program. The byte value 192 in a DATA statement is presented as the text characters “1”, “9”, and “2” and then if there is another value the comma separator between the values also occupies memory. This one value to POKE into one byte of memory requires four supporting bytes in DATA. And then after the program stores the value in memory the DATA statement continues to occupy memory, wasting space. Wasted space means reduced space for code and reduced features in large programs. In addition to DATA's memory space issue the other problem with reading DATA statements is BASIC's slow execution time. BASIC must loop for every data value; reading the data, storing it into memory, and then reading more data. Any significant amount of data provides a long, boring wait for the user. Many BASIC games share this “feature” of making the user wait for a long program initialization. The second test program for the BITS utilities illustrates this problem. The time to store several machine language utilities totaling only about 300 bytes in memory was long enough that the program's loading section was modified to output helpful progress messages to assure the user the program had not crashed. Now consider that one complete character set is 1,024 bytes, and a complicated program may need to setup several thousand bytes of data. Assembly language and some compiled languages do not have these same issues with data storage space. These languages can declare where data will occupy memory and define the initial values. This is saved with the assembled/compiled machine language program, so the same mechanism that loads the machine language program into memory also establishes the organized, initialized data in memory. So, what to do about BASIC's problems? Eliminating the space-wasting behavior means eliminating DATA statements filled with numbers, or somehow optimizing the contents. Strings could be used to represent a lot of data. One character of a string is conveniently one byte of information. But strings still have a few problems: ATASCII characters are not always the same as binary byte values, so some translation is needed. Representing cursor control characters can be problematic when a program is LIST'ed and then ENTER'ed. There are two characters that cannot be expressed at all in a quoted string – the ATASCII End of Line character and the quote character itself. If the data includes either of these unpresentable characters then the string as DATA must replace them with a different value that can be included, and then after assigning the string it must go back and insert the problem characters into their correct positions in the string. This means adding more data to identify the locations of these special characters. Furthermore, the DATA statements filled with strings still occupy memory after the data is assigned to a string variable, though the waste factor for string characters is closer to 1:1 rather than roughly 4:1 for numeric (byte) data. If a BASIC program completely eliminates the DATA statements then where else can a program get its data? Here is an idea – This program loads values into memory from DATA: 10 RESTORE 50 20 FOR I = 0 TO 7 30 READ D:POKE 1536+I,D 40 NEXT I 50 DATA 2,34,27,155,132,130,129,128 That program above has the same end result as this program loading values into memory from a file: 10 OPEN #3,4,0,"D1:MEMORY.BIN" 20 FOR I = 0 TO 7 30 INPUT #1,D:POKE 1536+I,D 40 NEXT I 50 CLOSE #1 The difference is that the file reading method leaves behind no redundant DATA occupying valuable code and memory space (aside from the code to load the data.) Whether reading eight bytes or 800 bytes the amount of code to read from a file is the same. So, how does the data get into the file? A little one-time work is required to write the data into the file. Here is the same original code, but instead of POKE'ing the data into memory it writes the data out to the file. Then, the original program can be changed to read the data from the file and POKE that into memory, and so eliminate the DATA statements. 1 REM MSAVEDAT.BAS 5 REM SAVE FILE FROM DATA 10 RESTORE 50 15 OPEN #1,8,0,"H1:MEMORY28.BIN" 20 FOR I=0 TO 7 30 READ D:? #1;D 40 NEXT I 45 CLOSE #1 50 DATA 2,34,27,155,132,130,129,128 There is a question that is not obvious at this point, but will be wedged in here now, because the answer determines the way the code should write data to and read data from the file, and ultimately the direction of an assembly language utility. The question is, “What data is in the file?” Most of the time I work with the Atari800 or Atari++ emulators in Linux to extend the lifespan of the real 8-bit hardware, so here I will detour into Linux for the benefit of tools that show exactly what is in the data file. First of all, the file itself containing the data written for the 8 bytes: -rw-rw-rw- 1 kenjen users 28 Feb 24 18:15 MEMORY28.BIN This file is intended to contain data for 8 bytes, so then why does the directory listing report the file contains 28 bytes? A hex dump utility shows the file contains the following information: 0000 32 9b 33 34 9b 32 37 9b 31 35 35 9b 31 33 32 9b 2.34.27. 155.132. 0010 31 33 30 9b 31 32 39 9b 31 32 38 9b 130.129. 128. The right side of the hex dump provides the explanation. The file contains the text representation (ASCII/ATASCII) of the numeric values. The byte $9B is the ATASCII CHR$(155), the Atari's End Of Line character, which appears after each value. Recall that BASIC prefers to read and write data using text representation of values. The example program uses PRINT (or ?) and INPUT which quietly translate between an internal representation and the text representation. This is BASIC's data abstraction versus the programmer's desire to have BASIC do what is meant, not what is written. The program's (poorly expressed) intent is to store and read bytes of memory. However, BASIC treats the numbers as bytes only within the context of PEEK and POKE instructions. So, then how to get data into the file that is just discrete byte values? Single characters are bytes, so using the CHR$() function will output numeric values as single characters (aka bytes), so that's potentially workable for output. But, then how about reading the bytes? A program using INPUT will still read the file contents as a string which means it will try to read bytes until it reaches an End of Line ($9B) character. So, this is also not a workable solution. Atari BASIC provides a method to write and read a file one byte at a time with the commands PUT and GET. The same example program using PUT instead of PRINT (or ?): 1 REM MSAVEDT0.BAS 5 REM PUT BYTES TO A FILE 10 RESTORE 50 15 OPEN #1,8,0,"H1:MEMORYT0.BIN" 20 FOR I=0 TO 7 30 READ D:PUT #1,D 40 NEXT I 45 CLOSE #1 50 DATA 2,34,27,155,132,130,129,128 The program above results in this file only 8 bytes long: -rw-rw-rw- 1 kenjen users 8 Feb 24 18:52 MEMORYT0.BIN and that file contains the eight values as individual bytes (Linux Hex dump): 0000 02 22 1b 9b 84 82 81 80 ."...... This program uses GET instead of INPUT to retrieve the data to store in memory: 1 REM MLOADDT0.BAS 5 REM GET BYTES FROM FILE 10 OPEN #3,4,0,"H1:MEMORYT0.BIN" 20 FOR I = 0 TO 7 30 GET #1,D:POKE 1536+I,D 40 NEXT I 50 CLOSE #1 So, now we know how using data files can save valuable memory space in BASIC, and how to optimize the file content to the actual bytes as they would be stored in memory. However, a fundamental problem with BASIC remains – the program must read the file data byte by byte during a loop, and BASIC's slow execution speed will turn any significant amount of data into a long and inconvenient wait. In fact, doing device I/O byte by byte in BASIC is slower than reading from DATA statements in memory, so this memory saving solution penalizes the program with even slower data loading. If only there was some kind of machine language solution that could read the bytes from a file as fast as possible. What to do, Toto?!? OSS's BASIC XL provides a precedent with the Bput and Bget commands that write and read arbitrary length blocks of memory directly to and from a file as fast as the device can transfer bytes which is far faster than BASIC's ability to loop for individual bytes. How does BASIC XL manage this? Is it simply reading individual characters in a loop at machine language speed? Or is it doing another trick? It turns out that bulk input and output of bytes is a feature provided by the Atari OS's Centralized I/O (CIO) routines, but the problem is that Atari BASIC does not support all the commands that CIO provides. Gaming Atari's CIO (or not) Many systems of the 8-bit era require the programmer use unique calls to read and write information to each kind of device. Each act of reading a disk file, a cassette file, and user input typed from a keyboard may require calling different entry points in the OS. Likewise, writing to a disk file, a cassette, the screen, or a printer may also require calling different OS routines. Even using two disk drives could require different OS calls. Input/Output programming on these systems can be tedious affairs of device-specific coding for every possible input/output option which deters programmers from even providing choices to users. But the Atari system is different. The Atari includes a standard, modular, reusable input/output model. Simply put, the programmer fills out a common data structure describing the input/output operation and makes a call to one address in the OS. This is a high level abstraction for device input/output. There are no sectors to consider, no serial communications to worry about, no fixed buffers in the system. Everything is a stream of data in or out, read or written on demand. In a very general way this is similar to the unix world's “everything-is-a-file” philosophy. Changing disk file output to screen or printer output requires only a different device/file name. The setup and the call to the OS are the same for all. Considering the Atari's Central I/O (CIO) was written in the late 70s this is nearly magical, and very under-appreciated behavior in an 8-bit computer. Atari CIO The Atari CIO defines a basic set of commands that every handler must be prepared to accept. (Listed in the chart below.) This doesn't necessarily mean every device must do every I/O command. A keyboard cannot do output, and a printer cannot do input. However, the device handler is responsible for sanely managing commands and safely replying that an incompatible command request is not implemented. Command Command Number Description Open 3 Same as BASIC's OPEN command Get Text Record 5 Similar to BASIC's INPUT command Get Characters (Bytes) 7 Similar to BASIC's GET command Put Text Record 9 Similar to BASIC's PRINT command Put Characters (Bytes) 11 Similar to BASIC's PUT command Close 12 Same as BASIC's CLOSE command Status 13 Same as BASIC's STATUS command Command numbers above this range are handler-specific operations. For example, commands 17 and 18 are specific to the screen device (“S:”) to perform graphics DRAWTO and Fill, respectively. Commands from 32 to 38 (and higher) perform various DOS file management functions for the “😧” device. Per the list above, everything provided by the base CIO commands appear to correspond to a BASIC language I/O command. Well, almost, but not quite – “Similar” is not the same as “Same”. There is a bit of a disconnect between how BASIC uses these CIO actions, and what the CIO actions can really accomplish. Atari BASIC does not actually use the 5/Get Text Record and 9/Put Text Record. These commands read and write a stream of text characters ending with the Atari End Of Line character which is the Atari OS/CIO's general definition of “Text Record”. Atari BASIC's PRINT and INPUT behaviors are more complicated than the “Text Record” model, because BASIC I/O activity occurs incrementally rather than in a complete record. INPUT can handle multiple variables in one line. PRINT outputs variables and strings as BASIC interprets the values. PRINT also uses semicolons to suppress the end of line, and commas cause tabs/columnar output which are not inherent abilities in the CIO 9/Put Text Record command. So, BASIC is not using the Text Record I/O commands and is managing the I/O by other means. Additionally, notice that the titles for command 7/Get Characters and command 11/Put Characters do not exactly match how BASIC uses those commands. Both commands move bytes – stress the plural: b-y-t-e-S. However, Atari BASIC uses these CIO commands in the most minimal manner to serve as PUT and GET which move only one byte. Since we're looking for a way to read or write an arbitrary number of bytes (plural) these two CIO commands appear to be exactly what we need. The CIO command list above comes from Atari's “BASIC REFERENCE MANUAL” discussion of BASIC's XIO command. This suggests that XIO is capable of exercising these commands. If this is true, then the XIO command could be used to run these CIO operations as CIO intended. That's the theory. The IOCB First, let's learn how CIO operations work. The next section will examine how the XIO command relates to the CIO operations. Earlier it was stated that the programmer fills out a common data structure describing the input/output operation. This data structure is called the Input/Output Control Block (or IOCB). Each of the eight input/output channels has a 16-byte, IOCB dedicated to it at fixed locations in memory starting at $340/832(dec) for channel 0, $350 for channel 1, and so on up to $3B0 for channel 7. So, it is easy to find the IOCB for a channel. Multiply the channel number by 16 and add that to $340. The IOCB tracks the state of I/O operations to the channel. Though the IOCB is 16 bytes long the programmer need only interact with a few of the bytes. Some of the bytes are maintained by the OS, and some are not typically used at all except for special device commands. The values are referred to by their offset from the start of the IOCB: ICCMD: IOCB + $2 This is the CIO command discussed above. ICSTA: IOCB + $3 This is the last error/status of the previously completed CIO command. ICBAL/ICBAH: IOCB + $4 and + $5 This is the 16-bit address (low byte and high byte) of the input or output buffer here. In the case of 3/Open and CIO commands for DOS operations on disk files this buffer is the address of the string for the device/file name. ICBLL/ICBLH: IOCB + $8 and + $9 This is the 16-bit length (low byte, high byte) of the data here. In the case of read and write operations (5, 7, 9, or 11) this is the number of bytes to read in or write out from the buffer. CIO will update this value indicating the number of bytes actually transferred. In the case of 3/Open and commands for DOS operations on disk files this is the length of the device/file name. ICAX1: IOCB + $A Auxiliary byte for the handler. This commonly indicates the Mode for the 3/Open command. CIO will maintain this value here. Meaning of Mode values: For files combine these values for the Mode: 8 - write 4 - read 1 - append For the disk/DOS specifically: 2 - open the directory. For the “S:” device additional values direct how the OS opens graphics mode displays: 16 - Create the text window. 32 - Do not clear screen memory. Finally, For the “E:” handler the value 1 added to the open state (12 + 1 = 13) enables forced read Mode from the screen as if the Return key were held down. ICAX2: IOCB + $B Auxiliary byte for the handler. For the “S:” handler this specifies the Graphics mode to open. (The GRAPHICS numbers that BASIC uses, not ANTIC modes.) For the “😄” device value 0 is normal inter-record gaps, and 128 is the faster, short inter-record gaps. Other serial devices may use specific values here. The programmer need not be concerned with much more in most situations. The other bytes in the IOCB are either the responsibility of CIO, or only used for specific device functions. For the sake of reference: ICHID: IOCB + $0 Set by the OS to the index into the handler table when the channel is currently open. If the channel is closed the default value is 255/$FF. ICDNO: IOCB + $1 Set by the OS to the device number when multiple devices of the same kind are in use - e.g. 1 for “D1:”, 2 for “D2:”. ICPTL/ICPTH: IOCB + $6 and + $7 CIO populates this with the jump address for the handler's single-character PUT routine. Atari BASIC uses this as a shortcut to output characters. ICAX3, ICAX4, ICAX5, ICAX6: IOCB + $C through + $F Optional auxiliary bytes for the handler. NOTE and POINT DOS operations use these locations. Atari BASIC's XIO BASIC's XIO command provides a generic interface to access CIO functions that BASIC does not directly implement with a built-in command. The diagram below shows how the XIO values relate to the CIO's IOCB fields: XIO cmdno, #aexp, aexp1, aexp2, filespec ↓ ↓ ↓ ↓ ↓ CIO ICCMD Channel number ICAX1 ICAX2 ICBAL + ICBAH, ICBLL + ICBLH The XIO arguments conveniently match the list of CIO's IOCB values that a programmer should manage. This should mean the XIO command can substitute for any other CIO I/O command (in theory). An important distinction concerning XIO behavior vs the usual CIO expectations is that the 3/Open command uses ICAX1 and ICAX2 values where most other CIO commands don't need to specify those values. Depending on the device and the CIO command the original values set by the 3/Open could be significant and should not be disturbed. However, XIO accepts ICAX1 and ICAX2 values on every command which potentially could allow a later command to overwrite the values set by 3/Open. If ICAX1 and ICAX2 are important for later commands then for safety's sake they should be remembered and restated on subsequent use of XIO. A variety of documentation describing XIO share a common mistake by describing the last argument as always a filespec (the device identifier, and filename if applicable). In reality, the last argument simply provides the data buffer and length for the CIO command. This buffer has variable purpose. It is expected to contain the filespec for 3/Open and DOS-specific file manipulation commands. For most other commands this argument provides the input or output buffer for data. Atari BASIC can use an explicit string or a DIMensioned string for the buffer argument to XIO. The contents of this string does not even matter for some commands – for example, the 18/Fill and 17/Drawto CIO commands for the “S:” device do not use the buffer, so they do not care what value is passed. Below is an example of XIO performing the 18/Fill command for the non-existent device “Q:”. This works, because the real device identifier, “S:”, is only needed when the screen device is opened and the 18/Fill command does not use the buffer. 1 REM XIOFILL.BAS 5 REM DO FILL ON MYTHICAL Q: DEVICE 10 GRAPHICS 5+16 20 COLOR 330 PLOT 70,45:DRAWTO 50,1040 DRAWTO 30,10:POSITION 10,45 50 POKE 765,3 60 XIO 18,#6,0,0,"Q:" 70 GOTO 70 XIO and CIO 11/Put Bytes Assuming the XIO command works as advertized it should give access to the CIO commands 7/Get Bytes and 11/Put Bytes to manage a stream of bytes of arbitrary length. Below is a program using XIO to write a binary file using the 11/Put Bytes command. For the sake of demonstrating the global nature of XIO the other BASIC commands to OPEN and CLOSE the file are also replaced by XIO performing CIO commands 3/Open and 12/Close: 1 REM MSAVEDT2.BAS 5 REM SAVE FILE FROM DATA BY XIO 10 RESTORE 15 DIM D$(8) 20 FOR I=1 TO 8 25 READ D:D$(I)=CHR$(D) 30 NEXT I 35 ICAX1=8:ICAX2=0 39 REM OPEN 40 XIO 3,#1,ICAX1,ICAX2,"H1:MEMORY2.BIN" 44 REM PUT BYTES 45 XIO 11,#1,ICAX1,ICAX2,D$ 49 REM CLOSE 50 XIO 12,#1,ICAX1,ICAX2,"H:" 60 DATA 2,34,27,155,132,130,129,128 Hey! That seemed to work! So, lets take a look at the MEMORY2.BIN file... -rw-r--r-- 1 kenjen users 255 Feb 27 16:58 MEMORY2.BIN What on earth?!? The string is 8 bytes, but the file contains 255 bytes? How weird. Let's see what hexdump in linux says about the contents... 0000 02 22 1b 9b 84 82 81 80 9b 08 00 00 00 00 40 01 ."...... [email protected] 0010 00 00 00 00 81 14 00 04 00 19 00 04 04 00 00 00 ........ ........ 0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ 0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ . . . 00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ 00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ....... The 8 bytes that the program intended to write are there at the beginning of the file where they should be, so that's one good thing. But, the rest of the file appears to be junk out to the length of 255 bytes. It looks like the write started with the designated data string and then kept on going through whatever memory followed the string. Make the following additions to test this theory... 17 DIM E$(26) 18 E$="This should not be output." After running the program again and putting the file through hexdump: 0000 02 22 1b 9b 84 82 81 80 9b 68 69 73 20 73 68 6f ."...... .his sho 0010 75 6c 64 20 6e 6f 74 20 62 65 20 6f 75 74 70 75 uld not be outpu 0020 74 2e 40 08 00 00 00 00 40 01 00 00 00 00 81 14 [email protected] @....... 0030 00 04 00 19 00 04 00 00 00 00 00 00 00 00 00 00 ........ ........ 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ . . . 00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ 00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ....... So, that confirms it. The eight characters from D$ string were output and then followed by whatever happened to be in memory after that string to a total length of 255 bytes. This would suggest a simple bug with the way Atari BASIC passed the output length to CIO, but there's something else in the output that tells us the problem is worse than that. The byte that follows the first eight bytes is $9b, the Atari End of Line character and which occupies the place in the output where the first character of E$ should appear. (Interesting.) That End of Line character is not part of the real data of either of the strings. This must mean that Atari BASIC intentionally output the End of Line after the D$ content as if it were performing PRINT. The odd part is that Atari BASIC accounted for this End of Line by skipping the next actual byte in memory which is the first character of E$. Then Atari BASIC figured out how many bytes remained until it reached 255 bytes and directed output of those bytes from memory. In the Olympics of buggy behavior this is a Track and Field gold medalist. What could have possessed them to do this? Perhaps this could be salvageable. The good part is the intended bytes were output intact at the beginning of the file. If the behavior is simply that Atari BASIC pads additional content, then this is a usable and (barely) tolerable situation for binary file output. So, let's see what happens with more data – such as half a kilobyte simulating an Antic mode 6 or 7 character set: 1 REM MSAVEDT3.BAS 5 REM SAVE LARGE FILE WITH XIO 15 DIM D$(512) 20 FOR I=1 TO 497 STEP 16 25 D$(I)="0123456789ABCDEF" 30 NEXT I 35 ICAX1=8:ICAX2=0 39 REM OPEN 40 XIO 3,#1,ICAX1,ICAX2,"H1:MEMORY3.BIN" 44 REM PUT BYTES 45 XIO 11,#1,ICAX1,ICAX2,D$ 49 REM CLOSE 50 XIO 12,#1,ICAX1,ICAX2,"H:" And after running the program the actual file length is... disappointment again... -rw-r--r-- 1 kenjen users 255 Feb 27 22:14 MEMORY3.BIN One point of good news is the hexdump utility shows the file does contain only the real bytes of the intended string up to 255 characters and that the last byte in the file is not substituted with the End Of Line: 0000 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 01234567 89ABCDEF 0010 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 01234567 89ABCDEF 0020 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 01234567 89ABCDEF . . . 00e0 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 01234567 89ABCDEF 00f0 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 01234567 89ABCDE That nails the coffin shut. Atari BASIC's use of the CIO 11/Put Bytes command is almost completely broken. For some reason Atari BASIC XIO believes the 11/Put Bytes must output a 255 byte, fixed-length block and Atari BASIC doctors the I/O activity to meet this expectation. Next we will look at CIO's 7/Get Bytes command and see if Atari BASIC's support is also broken for this command. XIO and CIO 7/Get Bytes First, let's verify that 7/Get Bytes can at least read the first 8 bytes from the 255 byte binary file: 1 REM MLOADDT.BAS 5 REM READ FILE USING XIO 10 DIM D$(8):D$(8)=" " 15 ICAX1=4:ICAX2=0 19 REM OPEN 20 XIO 3,#1,ICAX1,ICAX2,"H1:MEMORY2.BIN" 24 REM GET BYTES 25 XIO 7,#1,ICAX1,ICAX2,D$ 29 REM CLOSE 30 XIO 12,#1,ICAX1,ICAX2,"H:" 35 FOR I=1 TO 8 40 ? ASC(D$(I,I)), 45 NEXT I:? When it runs BASIC reports: 2 34 27 155 132 130 129 128 It looks like it is reading the data into the string correctly. But, is there anything else going on? Remember Atari BASIC thinks the write has to output 255 bytes. Maybe it is also doing something strange during the read. Lets see if it is reading more than directed: 1 REM MLOADDTX.BAS 5 REM READ FILE USING XIO 10 DIM D$(8):D$(8)=" " 11 DIM E$(255):E$="!":E$(255)="!":E$(2)=E$ 15 ICAX1=4:ICAX2=0 19 REM OPEN 20 XIO 3,#1,ICAX1,ICAX2,"H1:MEMORY2.BIN" 24 REM GET BYTES 25 XIO 7,#1,ICAX1,ICAX2,D$ 29 REM CLOSE 30 XIO 12,#1,ICAX1,ICAX2,"H:" 35 FOR I=1 TO 8 40 ? ASC(D$(I,I)), 45 NEXT I:? 50 ? E$ This is basically the same program with the addition of a large E$ declared and populated entirely with exclamation points, "!". If Atari BASIC reads only the 8 bytes it needs to populate D$ then E$ should be undisturbed and the program will end by displaying 255 uninterrupted exclamation points. But, this is the actual result: Unfortunately, this did not do what is expected or needed. BASIC overwrote E$ with the remaining data from the file. (An interesting bit of trivia is that the first character of E$ is preserved. This character corresponds to the End Of Line that BASIC had inserted in the output.) So, now we know that the CIO 7/Get Bytes command works well enough from Atari BASIC to retrieve short sequences of binary data as long as a buffer of 255 bytes is provided. Now to figure out if it can load longer data. Given the 255 character limit when using 11/Put Bytes the next program will test that limit for reading. First, we need a file that has more than 255 bytes. Recall that the earlier attempt to write 512 bytes actually failed, so here is a (much slower) program to make the 512 byte file as intended: 1 REM MSAVE512.BAS 5 REM WRITE 512 BYTES TO FILE 10 DIM D$(16):D$="0123456789ABCDEF" 15 OPEN #1,8,0,"H1:MEM512.BIN" 20 FOR I=1 TO 32 25 FOR J=1 TO 16 30 D=ASC(D$(J)) 35 PUT #1,D 40 NEXT J 45 NEXT I 50 CLOSE #1 Next is the program to test if Atari BASIC XIO has a 255 byte limit for the 7/Get Bytes command similar to the way it limits 11/Put Bytes: 1 REM MLOAD512.BAS 5 REM READ 512 BYTES FROM FILE 10 DIM D$(512) 15 D$="!":D$(512)="!":D$(2)=D$ 20 ICAX1=4:ICAX2=0 24 REM OPEN 25 XIO 3,#1,ICAX1,ICAX2,"H1:MEM512.BIN" 29 REM GET BYTES 30 XIO 7,#1,ICAX1,ICAX2,D$ 34 REM CLOSE 35 XIO 12,#1,ICAX1,ICAX2,"H:" 40 ? D$ D$ is declared 512 bytes long and filled with exclamation points. Then it attempts to read the 512 bytes from the file into D$. If this works properly the entire contents of D$ should show the "0" to "F" pattern read from the file all the way to the end. But this is what happens, instead: No joy for Atari BASIC's XIO. The result shows the first 255 characters of D$ are populated with the values from the file and the remainder of D$ is the exclamation points set during the program initialization. But, the horror is not over. Recall the MEMORYT0.BIN file created earlier that contains only 8 bytes? This program attempts to read just those 8 bytes from the file: 1 REM MLOAD8.BAS 5 REM READ THE 8 BYTES FROM FILE 10 DIM D$(8) 15 D$="!!!!!!!!" 20 ICAX1=4:ICAX2=0 24 REM OPEN 25 XIO 3,#1,ICAX1,ICAX2,"H1:MEMORYT0.BIN" 29 REM GET BYTES 30 XIO 7,#1,ICAX1,ICAX2,D$ 34 REM CLOSE 35 XIO 12,#1,ICAX1,ICAX2,"H:" 40 ? D$ And this is what happens when the program runs: ERROR- 136 AT LINE 30 The program gets an End Of File error during the XIO performing the 7/Get Bytes request. BASIC XIO expects to read 255 bytes from the file no matter the size of the string buffer supplied, even if the buffer is defined shorter. So, the bottom line is that Atari BASIC XIO has mangled use of the CIO 7/Get Bytes command similar to the 11/Put Bytes command. Here's a summary of what we have left of these CIO command as Atari BASIC has abused them: XIO for 7/Get Bytes is usable for reading binary data from 1 to 255 bytes. If the intended data is shorter than actual file size (of 255 bytes) then Atari BASIC will continue retrieving data from the file and storing it into memory up to that 255 byte maximum length. In order to complete this activity the file must have at least 255 bytes, and in the interest of safety the string buffer accepting the data should be 255 bytes. XIO for 11/Put Bytes is usable to write 1 to 255 bytes to a file with the understanding that anything shorter than 255 bytes will be padded to the length of 255 bytes with junk. In addition, Atari BASIC's capability is further restricted, because it only performs input and output to a a string variable. Saving and loading data to any arbitrary memory location is problematic. This could be circumvented with more involved coding to manipulate a string table entry to point to a specific memory addresses before the read or write. But, again, since BASIC insists on moving 255 bytes at a time, even this method isn't a great solution. We're not going to even bother trying that. In the next episode we'll look at a machine language replacement for XIO and its test program. For my thoughts are not your thoughts, neither are your ways my ways, declares the Lord. For as the heavens are higher than the earth, so are my ways higher than your ways and my thoughts than your thoughts. Isaiah 55:8-9
  11. Memory Copy ============================================================== Part 1 - Introduction http://atariage.com/forums/blog/576/entry-13175-part-1-of-11-simple-assembly-for-atari-basic/ Part 2 - Learn 82.7% of Assembly Language in About Three Pages http://atariage.com/forums/blog/576/entry-13176-part-2-of-11-simple-assembly-for-atari-basic/ Part 3 - The World Inside a USR() Routine http://atariage.com/forums/blog/576/entry-13177-part-3-of-11-simple-assembly-for-atari-basic/ Part 4 - Implement DPEEK() http://atariage.com/forums/blog/576/entry-13178-part-4-of-11-simple-assembly-for-atari-basic/ Part 5 - Implement DPOKE http://atariage.com/forums/blog/576/entry-13180-part-5-of-11-simple-assembly-for-atari-basic/ Part 6 - Various Bit Manipulations http://atariage.com/forums/blog/576/entry-13181-part-6-of-11-simple-assembly-for-atari-basic/ Part 7 - Convert Integer to Hex String http://atariage.com/forums/blog/576/entry-13182-part-7-of-11-simple-assembly-for-atari-basic/ Part 8 - Convert Integer to Bit String http://atariage.com/forums/blog/576/entry-13183-part-8-of-11-simple-assembly-for-atari-basic/ Part 9 - Memory Copy http://atariage.com/forums/blog/576/entry-13184-part-9-of-11-simple-assembly-for-atari-basic/ Part 10 - Binary File I/O Part 1 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13185-part-10-of-11-simple-assembly-for-atari-basic/ Part 11 - Binary File I/O Part 2 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13186-part-11-simple-assembly-for-atari-basic-the-end/ ============================================================== A number of features on the Atari benefit from fast memory copies. High speed data copying provides convenience to the user by reducing wait times for actions that would use slow, time-consuming BASIC loops. Copying a character set (1024 bytes) is a good example. High speed memory moves also enable use of Atari features that are not otherwise possible due to BASIC's speed. For example, vertical movement and animation of Player/Missile graphics in BASIC is not realistic, but a memory move function makes P/M graphics animation practical in an Atari BASIC program. Though Atari BASIC lacks a general purpose memory move there is a hack around this problem that exploits the way Atari BASIC manages strings. As simply as possible: A BASIC program may dig through the variable control structures and change the starting address of a string variable, effectively overlaying the string on any memory possible: screen memory, player/missile memory, color registers, character sets, hardware addresses, etc. String assignments then cause memory to be assigned or copied at near machine language speeds. The copy is done in ascending order and there is no consideration for source and destination memory (strings) that overlap. However, this string abuse method is a subject for an entirely different discussion and is not what will be done here. The subject of memory moves on the 6502 includes many considerations and is the inspiration for numerous discussions, arguments, and holy wars between programmers around the subject of speed, efficiency, optimization, and the odors emanating from the grandmothers of those who disagree with one's obvious and indisputable common sense. In short, although copying from A to B seems like a simple subject, there are a many choices and different methods to arrange a 6502 algorithm to copy memory. Topics that make a difference in code: How many bytes are being copied? More or less than 128 bytes? More or less than 256 bytes? More or less than 32K bytes? Does the code need to consider whether or not the source and destination memory overlap? Should the memory be copied in ascending or descending order? Is speed important? Should loops be unrolled into explicit code? Is the size of the code more important than speed? All of the above can start a group of programmers on a never-ending flame war. For the sake of defusing arguments I will admit that the result created here will not be everyone's idea of best, fastest and most efficient. We will follow the rule, “moderation in all things.” Well, more of a guideline than a rule. Let's say that we are copying four bytes from a source to a destination. The fastest way to copy is to do it directly and explicitly: LDA SOURCE STA DEST LDA SOURCE+1 STA DEST+1 LDA SOURCE+2 STA DEST+2 LDA SOURCE+3 STA DEST+3 That's about as fast as it gets on the 6502. Depending on whether or not source or destination is in Page Zero, this code uses about 4 to 6 bytes worth of instructions (total of 16 to 24 bytes just for this example!) and 6 to 8 cycles of CPU time for each byte it moves. That's all the good about it. Now the reality check: The code is not general purpose. When source and destination change then another block of code must be created. This method makes the assembly source code for a memory move of any substantial size very wordy, not to mention the tedious typing for the programmer. An explicit copy like this is done when performance is the ultimate goal. The next level of optimization is a loop to move a range of bytes: LDX #$00 LOOP LDA SOURCE,X STA DEST,X INX CPX #$04 BNE LOOP This code uses an index to copy bytes in ascending order and makes a comparison for the number of bytes. The code occupies 9 to 11 bytes (without the LDX initialization), roughly half the size of the explicit method. The size efficiency becomes greater the more bytes are copied. This code can copy 4 bytes, 10 bytes, or 100 bytes and remains the same size, while the earlier explicit method expands with every byte. However, this code uses 15 to 17 CPU cycles (not including the LDX initialization which occurs only once) for every byte it copies which is more than twice as long as the explicit copy. Additionally, this still uses absolute addresses and is not a general purpose, reusable routine. Here is a little optimization on this method: LDX #$03 LOOP LDA SOURCE,X STA DEST,X DEX BPL LOOP This version uses an index to copy bytes in descending order and eliminates the compare instruction by relying on the CPU negative flag changing when the index decrements from $00 to $FF. This reduces the code size to 7 to 9 bytes without the LDX initialization. Execution time (without the LDX) is reduced to 13 to 15 cycles per byte copied – just about twice as long at the explicit method. Again, like all other examples this uses absolute addresses and so is not a general purpose, reusable routine. A general purpose routine must use indirection instructions allowing the source and destination addresses to be different each time the program uses the routine. This means Page Zero locations must be initialized for source and destination:. LDA # <SOURCE STA ZSOURCE LDA # >SOURCE+1 STA ZSOURCE+1 LDA # <DEST STA ZDEST LDA # >DEST+1 STA ZDEST+1 ; LDY #$03 LOOP LDA (ZSOURCE),Y STA (ZDEST),Y DEY BPL LOOP This version is not so short. The initialization (executed once) is 18 bytes long. While the actual looping section is only 7 bytes it executes in 15 to 17 cycles due to the indirection. The advantage here is that the looping section is reusable. Another consideration of the indexed, looping methods is that they can copy a limited number of bytes. The maximum number of bytes a loop can copy using the X or Y register as an index is 256 bytes ($00 to $FF). The method of comparison or detection of the end of the copy loop can also limit the number of bytes. An earlier example copies in descending order uses BPL to detect the index wrapping around from $00, a positive value, to $FF, a negative value. This means the branching evaluation cannot encounter any other negative value which limits this code 129 bytes. 129? not 128? Why? LDX #$80 ; Start at +128 LOOP LDA SOURCE,X STA DEST,X DEX ; From here X as $7F descending BPL LOOP ; to $00 is valid It is possible to copy a specific number of bytes less than 256 in ascending order without using a comparison instruction, but, this is less obvious. This code example below alters the starting address to compensate for the starting index, so that the branch decision can rely on the CPU flag change when the index reaches zero: ; $00 - $04 = $FC LDX #$FC LOOP LDA SOURCE-$FC,X STA DEST-$FC,X INX ; Continues for $FD, $FE, $FF BNE LOOP ; and quits at index $00 So, then what do do when more there are more than 256 bytes to copy? In the simple loop examples just add another loop that copies more bytes with different source and destination addresses. But, when there is a lot of memory to copy this quickly becomes redundant. The advantage of using the indirection method is that the source and destination addresses in Page Zero can be easily modified and used to repeat the loop again. The example below copies 1024 bytes: LDX #$04 ; Number of 256 byte pages LDY #$00 LOOP LDA (ZSOURCE),Y STA (ZDEST),Y INY BNE LOOP ; Copy a page INC ZSOURCE+1 ; Increment addresses' INC ZDEST+1 ; high bytes DEX BNE LOOP ; Do another page The looping part is 14 bytes long. It can copy any number of 256 byte pages just by changing the X register. This is a practical routine for the Atari which has character sets 512 or 1024 bytes long. Player/missile graphics may use memory maps of 256 bytes. More generally, aligning any data to fit within the range of an index register allows reasonably compact code like this. The next problem is how to copy any number of bytes. Simply change perspective and think of the problem in two parts. First, if the number of bytes is 256 or greater then the previous page copy shown above can take care of all the whole, 256-byte pages. The high byte of the size provides the number of whole 256 byte pages. That leaves the size's low byte which specifies the remaining zero to 255 bytes. This second part just needs a slightly different byte copying loop that will stop early at a specific count. Assuming the source, destination, and size are all set into designated page 0 locations, then the relocatable, re-usable code could look something like this: MEMMOVE in Mac/65 Assembler Code 0100 ; MEMMOVE.M65 0105 ; 0110 ; GENERAL MEMORY MOVE 0115 ; 0120 ; GENERIC MEMORY MOVE FROM 0125 ; SOURCE TO DESTINATION 0130 ; ASCENDING. 0135 ; 0140 ; USR 3 ARGUMENTS: 0145 ; SOURCE == FROM ADDRESS 0150 ; DEST == TO ADDRESS 0155 ; SIZE == NUMBER OF BYTES 0160 ; 0165 ; RETURN VALUE IS BYTES COPIED. 0170 ; 0175 ZRET = $D4 ; FR0 $D4/$D5 Return Value 0180 ZARGS = $D5 ; $D6-1 for arg Pulldown loop 0185 ZSIZE = $D6 ; FR0 $D6/$D7 Size 0190 ZDEST = $D8 ; FR1 $D8/$D9 Destination 0195 ZSOURCE = $DA ; FR1 $DA/$DB Source 0200 ; 0205 .OPT OBJ 0210 ; 0215 *= $9200 ; Arbitrary. this is relocatable 0220 ; 0225 INIT 0230 LDY #$00 ; Make the return 0235 STY ZRET ; value clear to 0 0240 STY ZRET+1 ; by default. 0245 PLA ; Get argument count 0250 BEQ BYE ; Shortcut for no args 0255 ASL A ; Now number of bytes 0260 TAY 0265 CMP #$06 ; Source, Dest, Size 0270 BEQ PULLDOWN 0275 ; 0280 ; Bad arg count. Clean up for exit. 0285 ; 0290 DISPOSE ; Any number of arguments 0295 PLA 0300 DEY 0305 BNE DISPOSE 0310 RTS ; Abandon ship. 0315 ; 0320 ; Pull args into Page Zero. 0325 ; This code works the same 0330 ; for 1, 4, 8... arguments. 0335 ; 0340 PULLDOWN ; arguments in Y 0345 PLA 0350 STA ZARGS,Y 0355 DEY 0360 BNE PULLDOWN 0365 ; 0370 ; Since we're good to start the 0375 ; copy, then set the return 0380 ; value to the size. 0385 ; 0390 LDA ZSIZE+1 0395 STA ZRET+1 0400 LDA ZSIZE 0405 STA ZRET 0410 ; 0415 ; Moving full 256 byte pages or not? 0420 ; 0425 LDY #0 0430 LDX ZSIZE+1 ; Number of pages is 0435 BEQ MOVEPARTIAL ; Zero so, try partial. 0440 ; 0445 ; Copy full index range of 256 bytes. 0450 ; 0455 MOVEPAGE 0460 LDA (ZSOURCE),Y 0465 STA (ZDEST),Y 0470 INY 0475 BNE MOVEPAGE ; Y rolled $FF to $00 0480 INC ZSOURCE+1 ; Next page src 0485 INC ZDEST+1 ; next page dst 0490 DEX ; this page done 0495 BNE MOVEPAGE ; Non-zero means more 0500 ; 0505 ; A partial page remains? 0510 ; 0515 MOVEPARTIAL 0520 LDX ZSIZE ; Low byte remainder. 0525 BEQ BYE ; Zero, exit 0530 ; 0535 MOVEMEM 0540 LDA (ZSOURCE),Y 0545 STA (ZDEST),Y 0550 INY ; Copy ascending. 0555 DEX ; and subtract count. 0560 BNE MOVEMEM 0565 BYE 0570 RTS 0575 ; 0580 .END MEMMOVE copies any number of bytes in ascending order from the source to destination. Earlier the article mentioned an Atari BASIC string hack that assigns strings to specific memory addresses and uses the string assignment action to copy from a source address to a target address. String assignments work in ascending order. Therefore, this routine achieves the same result as the string method (ascending copy) with a bit less hacking of the BASIC variable table. Copying in reverse order or automatically detecting source and target overlap would add more code for options that are not as frequently needed. This is certainly not the highest performing option possible. But, it is fairly compact and uses Page zero allowing the routine to be general-purpose, and reusable, and that is a reasonable goal for a routine to support Atari BASIC. If this discussion concerned writing an entire video game in assembly then the code would focus on execution time and use unrolled loops or other bells and whistles for copying faster at the expense of code size. Testing MEMMOVE The Atari BASIC program below, TESTMOVE.BAS, reasonably verifies operation of the memory move utility works as expected: 100 REM TEST MEMORY MOVE OPERATIONS 105 REM 110 GRAPHICS 0:POKE 710,0:POKE 82,0 115 DIM S$(258),D$(259) 120 GOSUB 503:REM RESET SRC AND DST 125 GOSUB 10000:REM LOAD MEMMOVE 130 REM RUN TESTS FOR 8,255,256,257 135 RESTORE 230 140 READ MSIZE 145 IF MSIZE<1 THEN ? "Done":END 150 ? "Testing move size ";MSIZE;" . . . "; 155 X=USR(MMOV,ADR(S$),ADR(D$)+1,MSIZE) 160 DCOUNT=0 165 FOR I=1 TO 259 170 IF D$(I,I)="*" THEN DCOUNT=DCOUNT+1 175 NEXT I 180 IF DCOUNT=MSIZE THEN ? "OK":GOTO 190 185 ? "FAILED! ";DCOUNT;" <> ";MSIZE 190 GOSUB 504:REM RESET DST 195 GOTO 140 200 REM 205 REM NUMBER OF BYTES TO MOVE FOR 210 REM EACH TEST. TESTS LESS THAN 215 REM ONE PAGE AND THE BORDER 220 REM CONDITIONS AROUND ONE PAGE. 225 REM 230 DATA 8,255,256,257,-1 235 END 500 REM 501 REM RESET MEMORY 502 REM 503 S$="*":S$(258)="*":S$(2)=S$ 504 D$=".":D$(259)=".":D$(2)=D$ 505 RETURN 9997 REM 9998 REM SETUP ML MEMMOVE UTILITY 9999 REM 10000 DIM MM$(68) 10001 MMOV=ADR(MM$) 10002 RESTORE 24000:? "Loading MMOV..." 10003 FOR I=0 TO 67 10004 READ D:POKE MMOV+I,D 10005 NEXT I:? 10006 RETURN 23996 REM H1:MEMMOVE.OBJ 23997 REM SIZE = 68 23998 REM START = 37376 23999 REM END = 37443 24000 DATA 160,0,132,212,132,213,104,240 24001 DATA 58,10,168,201,6,240,5,104 24002 DATA 136,208,252,96,104,153,213,0 24003 DATA 136,208,249,165,215,133,213,165 24004 DATA 214,133,212,160,0,166,215,240 24005 DATA 14,177,218,145,216,200,208,249 24006 DATA 230,219,230,217,202,208,242,166 24007 DATA 214,240,8,177,218,145,216,200 24008 DATA 202,208,248,96 The program tests different sizes to verify the partial and full page copy loops, and also tests the border conditions around a full page copy. After each each copy it tests the contents of the destination memory counting all the locations that were changed by the memory move. Successful output will look like this: Below are the source files and examples of how to load the machine language routine into BASIC included in the disk image and archive: MEMMOVE File List: MEMMOVE.M65 Saved Mac/65 source MEMMOVE.L65 Mac/65 source listing MEMMOVE.T65 Mac/65 source listed to H6: (linux) MEMMOVE.ASM Mac/65 assembly listing MEMMOVE.TSM Mac/65 assembly listing to H6: (linux) MEMMOVE.OBJ Mac/65 assembled machine language program (with load segments) MEMMOVE.BIN Assembled machine language program without load segments MEMMOVE.LIS LISTed DATA statements for MEMMOVE.BIN routine. MEMMOVE.TLS LISTed DATA statements for MEMMOVE.BIN routine to H6: (linux) MAKEMMOV.BAS BASIC program to create the MEMMOVE.BIN file. This also contains the MEMMOVE routine in DATA statements. MAKEMMOV.LIS LISTed version of MAKEMMOV.BAS MAKEMMOV.TLS LISTed version of MAKEMMOV.BAS to H6: (linux) TESTMOVE.BAS BASIC program that tests the MEMMOVE USR() routine. TESTMOVE.LIS LISTed version of TESTMOVE.BAS. TESTMOVE.TLS LISTed version of TESTMOVE.BAS to H6: (linux) ZIP archive of files: Move_Disk.zip Tar archive of files (remove the .zip after download) Move_Disk.tgz.zip Great peace have those who love your law; nothing can make them stumble. Psalm 119:165
  12. DPOKE ============================================================== Part 1 - Introduction http://atariage.com/forums/blog/576/entry-13175-part-1-of-11-simple-assembly-for-atari-basic/ Part 2 - Learn 82.7% of Assembly Language in About Three Pages http://atariage.com/forums/blog/576/entry-13176-part-2-of-11-simple-assembly-for-atari-basic/ Part 3 - The World Inside a USR() Routine http://atariage.com/forums/blog/576/entry-13177-part-3-of-11-simple-assembly-for-atari-basic/ Part 4 - Implement DPEEK() http://atariage.com/forums/blog/576/entry-13178-part-4-of-11-simple-assembly-for-atari-basic/ Part 5 - Implement DPOKE http://atariage.com/forums/blog/576/entry-13180-part-5-of-11-simple-assembly-for-atari-basic/ Part 6 - Various Bit Manipulations http://atariage.com/forums/blog/576/entry-13181-part-6-of-11-simple-assembly-for-atari-basic/ Part 7 - Convert Integer to Hex String http://atariage.com/forums/blog/576/entry-13182-part-7-of-11-simple-assembly-for-atari-basic/ Part 8 - Convert Integer to Bit String http://atariage.com/forums/blog/576/entry-13183-part-8-of-11-simple-assembly-for-atari-basic/ Part 9 - Memory Copy http://atariage.com/forums/blog/576/entry-13184-part-9-of-11-simple-assembly-for-atari-basic/ Part 10 - Binary File I/O Part 1 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13185-part-10-of-11-simple-assembly-for-atari-basic/ Part 11 - Binary File I/O Part 2 (XIO is Broken) http://atariage.com/forums/blog/576/entry-13186-part-11-simple-assembly-for-atari-basic-the-end/ ============================================================== Writing a two-byte, 16-bit value (DPOKE) goes hand-in-hand with reading (DPEEK). An 8-bit computer environment has many opportunities for managing 16-bit address and the Atari environment is no exception. Address of display lists, Address of screen memory. Addresses of buffers. Address pointers abound. OSS BASIC XL provides the DPOKE command to perform a 16-bit, two-byte write to a specified memory location. Like DPEEK, this can be duplicated in regular Atari BASIC, although much slower. So, in BASIC XL the action: Dpoke Address, Value is frequently seen in Atari BASIC programs expressed as: POKE ADDRESS, VALUE - INT( VALUE / 256 ) * 256 POKE ADDRESS + 1, INT( VALUE / 256 ) That’s a bit more complicated than DPEEK. Here the value must be broken down into the high byte (integer result of the value divided by 256) and the low byte (the remainder after division), and then the two values assigned to the two consecutive bytes in memory in low byte, high byte order. This can also be worked into a reusable subroutine in Atari BASIC: 10 DPOKE=28500 20 ADDRESS=560:VALUE=39968:GOSUB DPOKE 30 END. . . 28497 REM IMPLEMENT DPOKE 28498 REM INPUT = ADDRESS 28499 REM INPUT = VALUE 28500 HB=INT(VALUE/256) 28501 POKE ADDRESS,VALUE-HB*256:POKE ADDRESS+1,HB 28502 RETURN This is still fairly simple code. A small difference here is the high byte is calculated and retained to avoid multiple occurrences of the same floating point division. But, again, expressed in Atari BASIC this is fairly slow using one floating point division and one multiplication. As before, applying assembly language rocketry yields: DPOKE in Mac/65 Assembler Code 0100 ; DPOKE 0105 ; 0110 ; Write a 16-bit word into 0115 ; the specified address. 0120 ; 0125 ; USR 2 arguments: 0130 ; Addr == address to write. 0135 ; Val == Value to write. 0140 ; 0145 ; USR return value is 0. 0150 ; 0155 ; Use the FR0 FP register. 0160 ; The return value for BASIC 0165 ; goes in FR0. 0170 ; No FP is used so all of FR0 0175 ; (and more FP registers) can 0180 ; be considered available. 0185 ; 0190 ZRET = $D4 ; FR0 $D4/$D5 Return value 0195 ZARGS = $D5 ; $D6-1 for arg Pulldown loop 0200 ZVAL = $D6 ; FR0 $D6/$D7 Value 0205 ZADDR = $D8 ; FR0 $D8/$D9 Address 0210 ; 0215 .OPT OBJ 0220 ; 0225 ; Arbitrary. This is relocatable. 0230 ; 0235 *= $9600 0240 ; 0245 INIT 0250 PLA ; argument count 0255 TAY 0260 BEQ EXIT ; shortcut for no args 0265 ASL A ; now number of bytes 0270 TAY 0275 CMP #$04 ; Value, Address 0280 BEQ PULLDOWN 0285 ; 0290 ; Bad args. Clean up for exit. 0295 ; 0300 DISPOSE ; any number of args 0305 PLA 0310 DEY 0315 BNE DISPOSE 0320 BEQ EXIT 0325 ; 0330 ; This code works the same 0335 ; for 1, 4, 8 ... arguments. 0340 ; 0345 PULLDOWN 0350 PLA 0355 STA ZARGS,Y 0360 DEY 0365 BNE PULLDOWN 0370 ; 0375 ; Y is already zero here. 0380 ; 0385 LDA ZVAL 0390 STA (ZADDR),Y 0395 INY ; now Y is 1 0400 LDA ZVAL+1 0405 STA (ZADDR),Y 0410 ; 0415 ; On failure Y = 0 0420 ; On Success Y = 1 0425 ; 0430 EXIT ; 0435 STY ZRET 0440 STY ZRET+1 0445 RTS ; bye. 0450 ; 0455 .END The error detection and handling have a few differences from DPEEK. The DPOKE routine does not inherently require a response value where DPEEK does, so the DPOKE code does not have separate, early-exit code and uses only one place to set the response value merely to indicate general success or failure. This code uses an additional Page Zero value to accept the value to write to the address: 0190 ZRET = $D4 ; FR0 $D4/$D5 Return value 0195 ZARGS = $D5 ; $D6-1 for arg Pulldown loop 0200 ZVAL = $D6 ; FR0 $D6/$D7 Value 0205 ZADDR = $D8 ; FR0 $D8/$D9 Address The real work part of the code is obviously different since writing bytes into memory (DPOKE) is not the same as reading bytes from memory (DPEEK): 0375 ; Y is already zero here. 0380 ; 0385 LDA ZVAL 0390 STA (ZADDR),Y 0395 INY ; now Y is 1 0400 LDA ZVAL+1 0405 STA (ZADDR),Y The DPOKE version above conforms to my standard plan (more or less) for stack management and error handling. Most of the remaining utilities will stick with this plan. However, for the sake of (averting) argument there are admittedly more optimal ways to accomplish this depending on the programmer's definition of optimal. For instance, the value to write to the address need not be temporarily stored in Page Zero. After the code pulls the target address from the stack and establishes it in Page Zero it could pull the value and directly store it to the target address, like this: 0375 ; Y must be 1 here. 0380 ; 0385 PLA ; high byte 0390 STA (ZADDR),Y 0395 DEY ; now Y is 0 0400 PLA ; low byte 0405 STA (ZADDR),Y That does look clever as it subtracts two bytes from the code, and removes ZVAL from Page Zero. However, to make this work the argument handling must be different to pull two, not four bytes worth of arguments, and the Y value must be reset to 1 before arriving at this code, and the error return value needs to be reworked. In other words, the code savings in one place may be consumed by code needed in another place. The standardized approach may not be the most optimal, but it is conceptually consistent, flexible, and doesn't need to be re-factored from scratch for each different routine. Also, regardless of the degree of inefficiency in this less-than-optimal method the execution time is negligible compared to slower Atari BASIC. More time is spent by Atari BASIC converting the floating point values into 16-bit integers to pass as arguments to the machine language routine than the amount of time for execution of the the machine language routine. Testing DPEEK and DPOKE The Atari BASIC program below, TESTDPK.BAS, demonstrates how to load the machine language routines into strings and it tests the two routines: 0 REM H1:TESTDPK.BAS 100 REM TEST DPEEK AND DPOKE USR() TOOLS 110 GRAPHICS 0:POKE 710,0:POKE 82,0 120 GOSUB 10000 130 REM 140 REM TEST DPEEK 150 REM 155 ? "*** DPEEK ***" 160 DL=PEEK(560)+256*PEEK(561) 170 ? "BASIC Dpeek Display List = ";DL 180 DL=0 190 DL=USR(DPEEK,560) 200 ? "USR() Dpeek Display List = ";DL 210 REM 220 REM TEST DPOKE 230 REM 240 CL=10+256*68:REM 711=10,712=68 250 X=USR(DPOKE,711,CL) 260 REM 270 REM VERIFY WITH DPEEK 280 REM 290 ? "*** DPOKE ***" 300 ? "10 + 256 * 68 = ";10+256*68 310 CL=PEEK(711)+256*PEEK(712) 320 ? "BASIC After Dpoke = ";CL 330 CL=0 340 CL=USR(DPEEK,711) 350 ? "USR() After Dpoke = ";CL 360 END 970 REM 980 REM DPEEK AND DPOKE 990 REM 10000 DIM DPE$(36),DPO$(38) 10001 DPEEK=ADR(DPE$):DPOKE=ADR(DPO$) 10010 RESTORE 27000 10011 FOR I=0 TO 35 10100 READ D:POKE DPEEK+I,D 10101 NEXT I 10110 FOR I=0 TO 36 10111 READ D:POKE DPOKE+I,D 11000 NEXT I 11001 RETURN 26999 REM dpeek.obj 27000 DATA 104,168,240,10,10,168,201,2 27010 DATA 240,9,104,136,208,252,132,212 27020 DATA 132,213,96,104,153,213,0,136 27030 DATA 208,249,177,214,133,212,200,177 27040 DATA 214,133,213,96 28999 REM dpoke.obj 29000 DATA 104,168,240,28,10,168,201,4 29001 DATA 240,6,104,136,208,252,240,16 29002 DATA 104,153,213,0,136,208,249,165 29003 DATA 214,145,216,200,165,215,145,216 29004 DATA 132,212,132,213,96 First the program performs DPEEK the slow way in BASIC by calculating the 16-bit address of the display list (at locations 560 and 561) with a multiply in BASIC (line 160). Then the program performs the same action using the DPEEK USR() routine (line 190). The value determined by each method is displayed for comparison: Next the program tests the DPOKE USR() routine by assigning a 16-bit value to locations 711 and 712. First it calculates the 16-bit value and reports it. Then it performs DPOKE via the USR() routine (Line 250). Then it retrieves the contents of the two memory locations by the slower BASIC method for DPEEK and by the DPEEK USR() routine. Finally, it reports the value determined by each method to verify the value was written to memory correctly: Below are the source files and examples of how to load the machine language routine into BASIC included in the disk image and archive: DPOKE File List: DPOKE.M65 Saved Mac/65 source DPOKE.L65 Mac/65 source listing DPOKE.T65 Mac/65 source listed to H6: (linux) DPOKE.ASM Mac/65 assembly listing DPOKE.TSM Mac/65 assembly listing to H6: (linux) DPOKE.OBJ Mac/65 assembled machine language program (with load segments) DPOKE.BIN Assembled machine language program without load segments DPOKE.LIS LISTed DATA statements for DPOKE.BIN routine. DPOKE.TLS LISTed DATA statements for DPOKE.BIN routine to H6: (linux) MAKEDPOK.BAS BASIC program to create the DPOKE.BIN file. This also contains the DPOKE routine in DATA statements. MAKEDPOK.LIS LISTed version of MKDPOKE.BAS MAKEDPOK.TLS LISTed version of MKDPOKE.BAS to H6: (linux) TESTDPK.BAS BASIC program that tests the DPEEK and DPOKE USR() routines. TESTDPK.LIS LISTed version of TESTDPK.BAS. TESTDPK.TLS LISTed version of TESTDPK.BAS to H6: (linux) ZIP archive of files: Dpoke_Disk.zip Tar archive of files (remove the .zip after download) Dpoke_Disk.tgz.zip For we are his workmanship, created in Christ Jesus for good works, which God prepared beforehand, that we should walk in them. Ephesians 2:10
  13. From the album: Chiseler

    Atari computer classic type-in-code video game. Youtube link to video since album doesn't seem to takevideos.
  14. Understanding Atari Graphics by Michael Boom 1982. 101 Atari Computer Programming Tips and Tricks by Alan North 1983. Your Atari Computer - a guide to Atari 400/800 personal computers by Ion Poole 1982. An Atari for Kids by Sharon Boren 1984. All books are in used condition with various stages of wear. If these do not sell, they will go to Salvation Army. Media Mail from 80138. Thank you.
  15. Here we have a Quickshot IX "Deluxe Joyball Controller" by Spectravideo (SVI). You don't see too many of them around and it's a very interesting concept. Works best for maze-type games in my opinion. It's not a trackball, and rather you push the ball in the direction you want to go and it will click (think microswitches). It is meant to be played horizontally, not vertically (note the left hand/right hand toggle switch). It also has an autofire switch. All four suction cups on bottom are present. This controller is in good shape cosmetically and has been fully tested and functions as it should. Please see the attached pictures for more details. $25 including shipping to anywhere in the US takes it. Willing to ship to Canada but will need a little extra for shipping across the border (and all bets are off on transit time). Shoot me a PM with questions or to finalize a deal. Thanks!
  16. I rolled up a quick-n-dirty simple retro birthday card for a friend. (No music. Maybe for next year's card.) (And, No, FillInTheBlank is not their actual name. ) Assembly code. Redefined character sets do the animated flames. Display kernel updating colors on every scan line. lots of laziness in evidence. Too lazy to actually do a VBI or DLI. Assembly code is here if anyone is interested: https://github.com/kenjennings/WIP-HBFITB Video is on youTube: https://youtu.be/WLELDFDT3uM
  17. This is (again :)) Dracon from TAQUART Group. I have the honor to present another interview with a person known (this time) for his excellent games on Atari XL/XE. At the time of the interview he is currently 30 years old and... it's English programmer Ivan Mackintosh, to whom we owe such hits as CRUMBLE`s CRISIS or REBOUND (giving only a few of the collection). Despite the passage of time, however, I decided to publish it, with the consent of the Ivan himself... This interview was based on a series of our emails from 1999 year and was firstly published at Polish website Atari.Area. D = Dracon I = Ivan Mackintosh D - Hello, at first I must say that you were a really great Atari 8-bit programmer. I remember you from such great games as BLACK LAMP or CAVERNIA (was it your latter game on Atari ?). I - Hi. I am glad that you like my games. CAVERNIA was not my last game, because I wrote one more for Atari, which has never been released - "TUBE BADDIES". It's a two-player game where you have to shoot down the monsters and stick holes in the pipes so that no new monsters appear. It was another game made with Richard Munns - so, as usual, there is great music and graphics. My first game written in assembler 6502 was REBOUND. Previous games (Crumble`s Crisis and continuation - Space Lobsters which is only good for graphics - no playability) were written in compiled Basic. This is probably the reason why they are so slow. D - The English magazine NEW ATARI USER once published a review of your game TAGALON. I also read there that there was a big break between writing and publishing this game... Is it true ? I - I think so, as I've never seen it in the sold version or even the cover ! D - So it seems that you didn't make much money writing games for Atari... Am I right ? I - I had a promised fee of 1500 English pounds (9500 PLN ?) for Black Lamp and 2000 English pounds (13000 PLN ?) for Tube Baddies game. Since they were never properly spent, we didn't get that fee. These two games were also the biggest earner. So in fact, when all the money was divided between Richard and me, we didn't have that much for 5-6 years of Atari XL programming. Certainly not enough to do it as a full-time job. D - Where did you get the inspiration your games from ? I - TAGALON was similar to SABRE WULF (from ZX SPECTRUM) for 2 players. TUBE BADDIES was inspired by another spectrum game - COOKIE. We were asked by Atari company to create BLACK LAMP. REBOUND was an attempt to write a sports game. And the other games just "happened" (without direct inspiration). D - Have you programmed games on a "clean" Atari or with the help of e.g. Atari ST (I'm asking in the sense of creating games on an 8-bit computer)? I - The first two games (CRUMBLES CRISIS and SPACE LOBSTERS) were written in Atari Basic and then compiled. It took two 1050 stations to speed up the compilation to about half an hour. I used a software assembler (Synapse Synassembler) to do the REBOUND. The rest of the games were programmed using my cartridge with MAC-65 assembler. All games were encoded on my faithful 800XL. D - And how did it look like to create e.g. music ? I - Richard used a synthesizer to work out the melody. Once he composed it, he manually translated the notes into values in the Basic's DATA command. When it was done, I converted his music player into an assembler and run it on VBI interrupts. D - Can you tell what is happening now with other famous people from Atari XL, like programmer Ian Copeland or musician Adam Gilmore ? I - Unfortunately I can't help it - I never talked to these people. D - Do you know that there are still people in Poland who write amazing programs, especially demos ? I - About three years ago (1996) I was in contact with one of the guys who made JOYRIDEcurrently doing demo. It was the last time my Atari 1050 drive was still working ! D - Well, what is your opinion about the so-called demo programs ? Is there any sense to write such programs instead of good games ? I - I think that some demos coming from Poland are excellent. It's just a shame that all this didn't happen 10 years before the Atari scene died. Anyway, as I see it, in the UK the 8-bit Atari scene is now extinct. D - Can you tell us what Richard Munns and HARLEQUIN (who has released the PLASTRON game, for example) are currently doing? I - Richard is messing up with PC computers, although he is not doing it professionally. I don't know what is happening with HARLEQUIN. Richard had contacts there when he was making music for it. As far as I can remember, he was cheated by HARLEQUIN because they did not pay him for his work. Richard didn't hear about HARLEQUIN later - maybe the company went bankrupt. D - Where do you work now ? I - I am a professional programmer (more precisely: "senior software engineer"), writing C++/COM applications for Reuters. D - Do you know if NEW ATARI USER magazine still exists ? I heard that it is (was?) available only for subscription... I - About 2 years ago (i.e. in 1997) I saw a copy of it on a computer show. It was A5 format. Really not much bigger than some leaflet. I don't think it's in print anymore. D - Do you sometimes turn on your 800XL (or emulate on PC) nowadays? I - None of that. My hobby nowadays is rather arcade machines. However, I still have 3 Atari computers (400, 800XL, 130XE) at home. D - So say something more about it. I - Currently I am more interested in games and arcade emulators. I have one slot machine and a NeoGeo console with 5 cartridges. I've never been to Poland, so I don't know anything about your resorts, but those in England usually have a lot of entertainment gaming machines, full of big "cabinets", containing a monitor, joystick, special table, etc. This is the kind of machine I have in my private room. D - You mentioned that SPACE LOBSTERS is only good for graphics. Yes, that's right, but why is it so difficult ? Why didn't you put any codes in your games (like Frank Cohen or Chris Murray) ? I - You mean, you haven't found any cheats yet ! There are none in CRUMBLES CRISIS nor in LOBSTERS SPACE. However, in CRUMBLES CRISIS you can rename the files so that you can play faster in the later stages of the game. In BLACK LAMP, as far as I remember, you can type "forest" and you will get infinite life. In CAVERNIA, type "tamsin" (my wife's name) to go to level 16 and "stevie nicks" (she's Richard's favorite pop artist) to move forward 1 level. It seems to me that this last code also works in TUBE BADDIES! D - Besides, I'm curious what happens when a player completes SPACE LOBSTERS or CRUMBLE CRISIS - is there any "final sequence" ? I - I don't remember what it is like in CRUMBLES... but there is nothing in SPACE LOBSTERS - we thought that the game is so bad that we don't have to do something like that, as nobody will get that far. So the game starts again, but it's more difficult. I think you have to collect more codes or something like that. Richard used to play it to get this far! D - In general - do you remember coding on Atari and you still have this ability ? I - I have Atari so I still remember those times. I think I could still code on it. It would be quite slow as I only remember what it can do, not how to do it. So I would have to take a good look at the book "Mapping the Atari". I would even like to program the Atari again, but I just don't have time. D - What's your favorite Atari game ? Mine is BLACK LAMP and DRACONUS. Both have a unique fantasy atmosphere and I am still impressed by the craftmaship in them. Appropriate, refined graphics, music and the rest - I think that these games take the maximum out of XL ! I - You've probably noticed from several of our games (Rebound, Tagalon, Tube Baddies) that we really like games for 2 players. One of our favorite games of all time was M.U.L.E. We also played a lot in International Karate, Drop Zone (we liked Archer McLean's games) and the games from Lucasfilm were also outstanding (Ballblazer, Rescue on Fractulas, etc.). D - And which games were favorites on other 8-bit computers? I - Our (my and Richard's) favourite games are arcade adventures. We grew up on ZX Spectrum games such as ATIC ATAC, SABRE WULF, ALIEN 8, etc. D - What is your opinion on your various "rewritten" (patched) games? I mean your games with trainers, intros, etc. ? I - After seeing it, I am generally flattered by the fact that people considered these games worth modifying ! D - In that case, what about such a case - a "transfer" of the CAVERNIA's hero in another game named DEIMOS? Is that OK? I - I really enjoyed playing DEIMOS. It reminded me very much of the kind of game that Richard and I would write together. As for the observations, it was a shame that the whole scenery was in gray tones and the colors of the hero were strange. I was tempted to make a modified version with other colors, but I noticed that the image with the game is compressed. I would need to have it unpacked on disk for modification. Although to tell you the truth, I don't have any free time for this. D - What made you stop writing games on XL/XE ? Haven't you thought about releasing e.g. TUBE BADDIES in Poland (here was a big market for this computer in mid 90's), Germany or somewhere else ? I - I went to the University and because of that I didn't have much free time, besides, companies in the UK were offering less and less money for games. I didn't realize there was a market outside my country and I didn't speak other languages either. D - Have you seen some games in which Richard Munns was involved (Plastron, Zero War)? How did you like them ? I - I saw Plastron during the creation, as Andy Dickinson was a friend of mine who lived in the neighboring city. However, I did not like his games very much. He also created the game COUNTDOWN. Nevertheless, the graphics and music in Plastron were good. D - Why was there no music or any ending in CAVERNIA ? Not enough memory (anyway, the hero's animation was great!) ? I - We didn't get a lot of money for the game - there was no incentive to make the game more beautiful. D - Going back to the emulation. Have you seen any Atari emulator on PC ? I - To be honest, I haven't touched any Atari stuff in a few years. I used an XL-it emulator by Markus Geitzen but about 3 or 4 years ago. This emulator was really good except for some problems with player/battle graphics (PMG) and the inability to overlay 2 players to get a third color on the bits I applied. This unfortunately meant that Richard's sprites didn't look so great. Now, however, there is a significant change - thank you very much for sending the Atari800Win emulator! It is excellent, so much better than the XL-it I had. It is more or less perfect ! I was so impressed that now I can even get rid of my real Atari. I was playing my games really well. D - Why did you choose Atari instead of C-64 (for creating games) ? I - We (me and Richard) did not choose, it just happened. We both had Atari for a few years before I started programming. It's a real shame that the C-64 came on the market (at least in the UK) more than Atari, as Atari was great for programming. I suppose if we were creating for the C-64, we could make more money. D - How long did it take you to create Black Lamp game ? The result was amazing and the game is just wonderful ! I also played Black Lamp on Amiga, but it was much worse version. I - Atari told us that they want the same Black Lamp as the Atari ST version. But when we started asking for game maps and other details, they couldn't provide that and then they let us encode what we wanted, if that was similar. I don't remember exactly, but I think it took 9 months to write (remember that it was all done on weekends and free evenings). Atari wanted to see how far we were every 2 months, so they could change things if they weren't satisfied with something. D - It's a shame there aren't any more games as well done as yours and Ian Copeland's. Maybe the 8-bit period was just one stage in creating games, a kind of training... Nowadays it is easier to use the advantages of the machine (good graphics cards) and make nice games (almost unoptimized algorithms and games require more and more CPU power). What do you think about it? I - Nobody cares anymore. There aren't many games that pull everything out of a machine now. TURISMO GAME on PSX was the last game I was really impressed with. It seems that many developers think that just nice graphics will make the game a hit. I completely disagree with that. I believe that gameplay is the most important thing. I can support it with the fact that I bought an arcade slot machine with a 1982 Mr.Do! game. It's a great game. D - You are right that certainly playability (inherent in the idea) is the most important thing in any game. So what do you say about the super hits from the 8-bit games (Blinky`s Scary School, World Soccer, Black Lamp, etc.), which were also released in 16-bit versions? They were certainly not appreciated as popular and good games, even though the idea was the same and the graphics were much better so what about this sad fact ? I - It seems to me that when people get new machines, they want newgames that use the power of the machine rather than some old games that just improved the graphics. Well, in the world of emulation it doesn't matter much now. Can you get Gameboy Color in Poland (small console) ? As I noticed, the DROPZONE game is soon to be released on it ! D - It's supposed to be available, but I don't know if in large quantities. Thanks for the interview ! I - No problem. At the end of this interview I'd add, that Ivan Mackintosh after stopping creating games on Atari also released some small PC utilities, which were related to XL emulation. These were quite a few programmers that helped to handle Atari floppy disk images: IMAGEMAN and ATARI DISK IMAGE MANAGER. Besides, one more interesting thing - at this address you can find a couple of small Ivan's games for NEOGEO Pocket! Polish version available here.
×
×
  • Create New...