Previous Thread
Next Thread
Print Thread
#109605 - 05/19/17 04:21 PM apple1 basic.zip vs. basica.zip: which is Apple's?  
Joined: Jun 2003
Posts: 30
Colin Howell Offline
Member
Colin Howell  Offline
Member

Joined: Jun 2003
Posts: 30
Mountain View, CA
I've been spending some time investigating the two Apple I BASIC files in the software list, and I'm now certain that "Apple I Basic" (basic.zip), the one labeled with an Apple part number and clearly recorded from a real cassette, is nevertheless a patched version, while "Apple I Basic (Alt)" (basica.zip), even though it seems to be a modern rerecording, still contains Apple's original code. I think we should keep both versions, but we need to relabel them.

(For those who haven't been able to load basic.zip, see my earlier posting on how to get it to load.)

The two BASIC images differ in only three areas: $EE53-$EE62, $EEA6-$EEC7, and $EF86-$EFB2; the rest of the code is identical. All three of these differing regions cover handler routines for various BASIC commands.

The first two areas include handlers for some commands which were undocumented in Apple I BASIC and were either disabled or nonfunctional. Some of these are recognizable from the Apple II as Integer BASIC commands; others were apparently abandoned. Wozniak was working on the Apple II design at the same time he was developing his BASIC, and it looks like he was writing the BASIC for both systems using a common code base, disabling certain functions which couldn't work on the Apple I.

The third region covers the handlers for the HIMEM= and LOMEM= commands, which reset the upper and lower bounds of the memory available to BASIC. In Apple I BASIC, these commands could not be included within a program, and they automatically erased any program in memory at the time. However, the basic.zip version has patched the handlers for these commands so that they always preserve the program in memory.

In the original version, both commands check to make sure that HIMEM will never be below LOMEM. (LOMEM= prints an error in this case, but HIMEM= doesn't.)

In the patched version, LOMEM= checks to make sure that the new value will not overlap the program, and prints an error if it would. Otherwise it resets the LOMEM boundary and clears all variables. HIMEM= checks to make sure that the new value is not lower (it is impossible to lower the HIMEM boundary with HIMEM= in this version), and if successful it moves the whole program up to the new HIMEM boundary. This last operation is the most complex of the changes, and it is spread over all three altered regions, overwriting the handlers for the undocumented, nonfunctional commands I already mentioned. These include:

  • HIMEM and LOMEM (functions to report the current HIMEM and LOMEM values, not to be confused with HIMEM= and LOMEM=)
  • COLOR (a function to report the current drawing color, not to be confused with COLOR=)
  • OFF (which became MAN in Integer BASIC, and turns off the automatic line-numbering mode started with the AUTO command)
  • HLIN col1 , col2 AT row
  • VLIN row1 , row2 AT col
  • VTAB row

Even in the original BASIC, none of these commands work properly; some will crash the interpreter.

The OFF command "works" but is practically useless, since once AUTO is activated, every input line gets a line number prefix and is treated as a program line, so the OFF command (which isn't legal in a program) will be rejected. The documented way to turn AUTO off is to press Control-D. (There are ways to force OFF to work; if you cause an input line to be canceled by typing Escape, by deleting all its characters, or by entering too many characters, AUTO will then be ignored for one input line, so there will be no line number and a non-program command like OFF will be accepted.)

The HLIN command is recognized by the parser but obviously required the Apple II's color graphics to work, and it crashes the interpreter due to an improperly terminated token handler.

The HIMEM, LOMEM, and COLOR functions are also recognized by the parser but don't work right; HIMEM returns the wrong value, while LOMEM puts the interpreter in a confused state, and COLOR (also clearly not applicable to the Apple I) isn't even implemented (it gives a *** RANGE ERR, but this may be a lucky accident).

VLIN and VTAB were disabled in the parser's syntax table, so trying to enter them will trigger syntax errors, but their identity can be determined both by their syntax table positions, which determined the token values assigned to them, matching the tokens for Integer BASIC's VLIN and VTAB, and by the code in their corresponding token handlers, which likewise matches up with Integer BASIC's VLIN and VTAB token handlers.

Since none of these undocumented commands worked, it's obvious why their handlers were chosen to be replaced by the patched version's HIMEM= handler.

There's further evidence pointing to what happened. If I understand correctly, the software list for apple1 was added to MESS in February 2012 by this commit (with an incorrect dataarea size parameter, fixed soon after), and the recording in basic.zip had been published in MP3 form in July 2008 on Michael Steil's weblog. Steil reveals that this recording came from Achim Breidenbach, creator of an early Apple I emulator, who in turn got it from a tape from Larry Nelson, one of the early Apple I owners. Likewise, Michael J. Mahon's disassembly was also created by first loading Achim Breidenbach's disassembly of the version from the Larry Nelson tape. (The code in Mahon's disassembly and the code in basic.zip match, except for a few differing bytes which are clearly errors in Mahon's code.)

Well, while looking up further information on Apple I BASIC and its HIMEM= and LOMEM= commands, at Tom Owad's "Applefritter" website I found two letters sent by Larry Nelson in March 1980 and January 1981, in which he talks about inoperative areas in the BASIC and putting his own code in there; in the second letter he specifically mentions having changed HIMEM= and LOMEM=. Quoting:

Code
... Before that I was working on BASIC.
   I've broken a lot of the code and am working
on cleaning out a lot of trash.  It looks like
they threw this thing together to get a computer
on the market fast.  Probably other used bits
and pieces from other listings, since there
are several places with bad listings.  Also found
USR, RNDX, and OFF statements on commands in
there.  USR and RNDX don't work, but OFF
turns off the auto-line #. (Try it by typing AUTO 10(r),
then type "escape", then OFF(r)).
   We have COLOR=, PLOT, HLIN, too.  It adds
up to 120 bytes in there + several commands that
we can't use.
   Now, if I can decipher how the ASCII is
coded for each command, I'll have it made!  Then
I'll be able to pull out those unused commands and
replace them with something useful.

Code
   The INKEY function could be put in
code.  The problem is that I've used some of
BASIC empty spots, and now I'm not sure
which places I've filled (HIMEM= and LOMEM=
changes, and that routine to randomize).
I goofed and didn't save a hard copy of
the changes.  (I make up for my stupidity with
ineptness!)
   In the original Apple BASIC, there are
several areas we could put "fixes":
E61C thru E622 =  7 Bytes
E98D   "  E997 = 11 Bytes
EE3E   "  EE67 = 37 Bytes (PLOT, COLOR=, OFF commands)
EEA6 thru EECA =  37 Bytes (HLIN, COLOR, Value of HIMEM and
                                                  LOMEM
                                               (don't work)
plus another 34 bytes strung over the 4K program in
banks of 6 or less.

Larry Nelson's remarks and interest in improving the BASIC explain a lot. It seems very likely to me that when he provided his Apple I BASIC cassette recording to Achim Breidenbach, the version he provided had his early patches to HIMEM= and LOMEM=. He might even have recorded them on the original cassette, and then forgotten about them; or maybe he just didn't think to mention the changes.

By contrast, another disassembly of Apple I BASIC can be found on Eric Smith's site; this one clearly came from a different source. Comparing its hexadecimal bytes with the version in basica.zip, they turn out to be byte-for-byte identical.

As I said at the start of this post, I think we should still keep both versions (Larry Nelson's patched version strikes me as itself an interesting historical artifact), but definitely rename and relabel them to better indicate their origins.

I will include direct comparisons of the unpatched and patched code in an additional post in this thread.

#109609 - 05/20/17 03:14 AM Re: apple1 basic.zip vs. basica.zip: which is Apple's? [Re: Colin Howell]  
Joined: Dec 2010
Posts: 43
Dagarman Offline
Member
Dagarman  Offline
Member

Joined: Dec 2010
Posts: 43
California
Corey Cohen provided a copy of BASIC that he loaded from an original BASIC tape and recorded with an iRig from an original Apple I.
It matches the softlisted basica version in the 3 differing memory areas.

Here is a copy of the tape.

#109610 - 05/20/17 09:57 AM Re: apple1 basic.zip vs. basica.zip: which is Apple's? [Re: Colin Howell]  
Joined: Jun 2003
Posts: 30
Colin Howell Offline
Member
Colin Howell  Offline
Member

Joined: Jun 2003
Posts: 30
Mountain View, CA
OK, here are the code comparisons I promised; sorry for the delay. These are assembly listings, dumped from MAME, which I have commented.

Especially when looking at blocks which I claim are original Apple code, it's important to keep in mind how this code was produced. Steve Wozniak was writing this directly in 6502 machine language without the benefit of an assembler, because at that time Apple could not afford any tools. He had to assemble the code by hand, and any changes in the location of a routine would have required fixing up all the addresses and relative branch offsets, again by hand. Also he was working on the design of the Apple II at the same time, which was clearly going to be the more important system (Jobs had to be persuaded not to abandon the Apple I before its BASIC was ready), and he was under intense time pressure. So it's not surprising that he used the same code for both systems. He would have had a very strong incentive to do the simplest possible hand-patching to make things work on the Apple I. It's no surprise that some cruft was left lying around.

Important addresses that show up in the code excerpts:

$CE,$CF: ACC, a general-purpose 16-bit accumulator.
$4C,$4D: HIMEM, 16-bit pointer to the top of BASIC's memory.
$4A,$4B: LOMEM, 16-bit pointer to the bottom of BASIC's memory.
$CA,$CB: PP, 16-bit pointer to the start of the current BASIC program (which extends from PP up to HIMEM).
$48,$49: (unnamed), a temporary 16-bit pointer in zero-page memory. Only used by the patched HIMEM= handler, not found in Apple's code.
$C8: TXTNDX, this variable may play several roles. (Its name comes from its use to index the input text buffer.)
$2D: V2 (Apple II Monitor variable), bottom row for vertical line.
$25: CV (Apple II Monitor variable), text cursor vertical position.
$F8: AUTOFLAG, the flag indicating whether AUTO line-numbering is on.
$E715: GET16BIT, a routine to retrieve a token's 16-bit argument and leave it in ACC.
$EE34: GETBYTE, a routine to retrieve a token's 8-bit argument and leave it in the 6502's accumulator.

The names for these are mostly arbitrary, since no source code is available for either Apple I BASIC or Integer BASIC. For consistency, the names I use here come from a disassembly of Integer BASIC made by Paul R. Santa-Maria, available here (PDF). (Although the assembler format used takes some getting used to, this still provided a valuable guide for comparing Apple I BASIC with Integer BASIC.)

All 16-bit values are stored in little-endian order.

I've listed the blocks in the order in which they are executed by the patched HIMEM= handler, which is the reverse of their memory ordering. I've put "spoiler" tags on the blocks so you can select which ones are visible, for easier reading and comparison.

Original Apple $EF80-$EFB5: HIMEM= and LOMEM= handlers, from basica.zip:
(The SCR command referred to here is Apple I BASIC's name for what Integer BASIC called the NEW command. SCR is a command seen in some older BASIC versions; it stands for "Scratch", as in "scratch the program".)

Code
; HIMEM= command handler:

; This does nothing (with a couple of presumably harmless side effects) if
; its argument is < LOMEM. It seems to have been intended to signal a
; *** RANGE ERR, but the sense of the carry flag is wrong for that.
; To get it right, the comparison would have to be reversed.
;
; Otherwise it changes HIMEM and erases the program, like a SCR command.

EF80: 20 15 E7      jsr $e715           ; Call GET16BIT (command argument -> ACC).
EF83: A4 CE         ldy $ce
EF85: C4 4A         cpy $4a
EF87: A5 CF         lda $cf
EF89: E5 4B         sbc $4b
EF8B: 90 1E         bcc $efab           ; Branch if ACC < LOMEM.
        ; (Do nothing; return with no error and a couple harmless side effects)

                                        ; If ACC >= LOMEM:
EF8D: 84 4C         sty $4c
EF8F: A5 CF         lda $cf
EF91: 85 4D         sta $4d             ; HIMEM = ACC

EF93: 4C AD E5      jmp $e5ad           ; Jump to SCR command handler.


; LOMEM= command handler:

; This signals a *** RANGE ERR if its argument is >= HIMEM; otherwise it
; changes LOMEM and erases the program, like a SCR command.

EF96: 20 15 E7      jsr $e715           ; Call GET16BIT (command argument -> ACC).
EF99: A4 CE         ldy $ce
EF9B: C4 4C         cpy $4c
EF9D: A5 CF         lda $cf
EF9F: E5 4D         sbc $4d
EFA1: B0 08         bcs $efab           ; Branch if ACC >= HIMEM.
                                        ; (Trigger "*** RANGE ERR".)

                                        ; If ACC < HIMEM:
EFA3: 84 4A         sty $4a
EFA5: A5 CF         lda $cf
EFA7: 85 4B         sta $4b             ; LOMEM = ACC
EFA9: 90 E8         bcc $ef93           ; Branch to jump to SCR handler.

EFAB: 4C CB EE      jmp $eecb           ; Triggers "*** RANGE ERR" if carry set.
        ; Just returns (with some presumably harmless side effects) if carry clear.


; The following appears to be leftover orphaned code; it looks like a HIMEM
; counterpart to the LOMEM function's handler at $EEBA:

EFAE: A5 4D         lda $4d
EFB0: 48            pha
EFB1: A5 4C         lda $4c
EFB3: 20 C9 EF      jsr $efc9

Patched $EF80-$EFB5: HIMEM= and LOMEM= handlers, from basic.zip:

Code
; HIMEM= command handler:

; This version does nothing (with the same presumably harmless side effects as
; the original) if its argument is < *HIMEM*. Thus it becomes *impossible* to
; lower HIMEM with this command once it has been raised. (This protects the
; program, but at the cost of flexibility.)
;
; Otherwise it moves the program upward to the new value for HIMEM, adjusting
; HIMEM and PP (the start-of-program pointer) to match. It does this via two
; additional patched blocks, using a new temporary pointer variable $48,$49.

EF80: 20 15 E7      jsr $e715           ; Call GET16BIT (command argument -> ACC).
EF83: A4 CE         ldy $ce
EF85: C4 4C         cpy $4c
EF87: A5 CF         lda $cf
EF89: E5 4D         sbc $4d
EF8B: 90 1F         bcc $efac           ; Branch if ACC < HIMEM.
        ; (do nothing; return with no error and a couple harmless side effects)

                                        ; If ACC >= HIMEM:
EF8D: 84 48         sty $48
EF8F: A5 CF         lda $cf
EF91: 85 49         sta $49             ; $48,$49 = ACC
EF93: 4C B6 EE      jmp $eeb6           ; Jump into move-program block...


; LOMEM= command handler:

; This version signals a *** RANGE ERR if its argument is >= PP (the start-of-
; program pointer); otherwise it changes LOMEM and *clears the variables*,
; like a CLR command.
;
; Thus, this LOMEM= command *always protects the program*, signaling an error
; if the new LOMEM would overlap it. If the user wants to force LOMEM high
; enough to do this, the program must first be either deleted explicitly or
; shrunk by editing or deleting lines.

EF96: 20 15 E7      jsr $e715           ; Call GET16BIT (command argument -> ACC).
EF99: A4 CE         ldy $ce
EF9B: C4 CA         cpy $ca
EF9D: A5 CF         lda $cf
EF9F: E5 CB         sbc $cb
EFA1: B0 09         bcs $efac           ; Branch if ACC >= PP.
                                        ; (Trigger "*** RANGE ERR".)

                                        ; If ACC < PP:
EFA3: 84 4A         sty $4a
EFA5: A5 CF         lda $cf
EFA7: 85 4B         sta $4b             ; LOMEM = ACC
EFA9: 4C B7 E5      jmp $e5b7           ; Jump to CLR command handler.


EFAC: 4C CB EE      jmp $eecb           ; Triggers "*** RANGE ERR" if carry set.
        ; Just returns (with some presumably harmless side effects) if carry clear.


EFAF: EA            nop
EFB0: EA            nop
EFB1: EA            nop
EFB2: EA            nop

EFB3: 20 C9 EF      jsr $efc9

Original Apple $EEA6-$EED2: various nonfunctioning command handlers, from basica.zip:

Code
; HLIN statement's comma-token handler ("HLIN <num> , <num> AT <num>"):
;
; (HLIN is undocumented, but allowed by the parser. This handler may crash the
; interpreter due to running off into another handler's code.)

EEA6: 20 34 EE      jsr $ee34           ; Call GETBYTE (command argument -> A).
EEA9: C5 C8         cmp $c8
EEAB: 90 BB         bcc $ee68           ; Branch if A < TXTNDX.
                                        ; (Trigger "*** RANGE ERR".)

                                        ; If A >= TXTNDX:
EEAD: 85            sta ...             ; (Zero-page STA opcode)
        ; From here, the code has been overwritten by the HIMEM handler
        ; immediately following, so it becomes garbage.


; HIMEM function handler for numeric expressions:
;
; (HIMEM is undocumented and doesn't work right. It's supposed to return the value
; of HIMEM, which is set with the "HIMEM=" command.)
;
; This also completely overwrites the entry point $EEB0 of HLIN's "AT" token handler.)

EEAE: A5 4D         lda $4d
EEB0: 48            pha
EEB1: A5 4C         lda $4c             ; Push HIMEM_H on stack, A = HIMEM_L.
EEB3: 20 08 E7      jsr $e708           ; Call a noun-stack routine.
EEB6: 68            pla
EEB7: 95 A0         sta $a0, x          ; Store the result?
EEB9: 60            rts
        ; (Perhaps a old calling convention that was later changed?
        ; In any case, this is broken.)


; LOMEM function handler for numeric expressions:
;
; (LOMEM is undocumented and is even more broken than HIMEM. It's supposed to return
; the value of LOMEM, which is set with the "LOMEM=" command.
;
; This also completely overwrites the entry point $EEBC of VLIN's comma token handler,
; but VLIN is disabled in the parser anyway. The tail end of the disabled handler's
; code can still be seen in the bytes $EEC3-$EEC5 after the first byte of the broken
; COLOR function handler below.)

EEBA: A5 4B         lda $4b
EEBC: 48            pha
EEBD: A5 4A         lda $4a             ; Push LOMEM_H on stack, A = LOMEM_L.
EEBF: 4C B3 EF      jmp $efb3           ; Jump off...
                                        ; (...into INPUT code. This is broken.)


; COLOR function handler for numeric expressions:
;
; (COLOR is undocumented and totally unimplemented. Presumably it was
; supposed to return the drawing color set with the "COLOR=" command.
; Of course, the Apple I doesn't support this.
;
; Only the starting opcode of the code is present. The rest is the tail end of
; VLIN's comma-token handler, followed by the entire disabled VLIN "AT" token
; handler.)

EEC2: A5            lda ...             ; (Zero-page LDA opcode)
        ; From here, the code is truncated.


; The tail end of VLIN's comma-token handler. The offset perfectly matches
; the $EEBC entry point.
;
; Note it stores to $2D. This is a zero-page variable for the VLINE routine
; at $F828 in the Apple II Monitor. 

EEC3: 85 2D         sta $2d             ; V2 = A
EEC5: 60            rts


; VLIN statement's "AT" token handler ("VLIN <num> , <num> AT <num>"):
;
; (This is disabled both in the parser and here, simply returning after loading and
; checking the arguments. The Apple II version in Integer BASIC instead jumps to its
; VLINE Monitor routine at $F828.)

EEC6: 20 34 EE      jsr $ee34           ; Call GETBYTE (command argument -> A).
EEC9: C9 28         cmp #$28
EECB: B0 9B         bcs $ee68           ; Branch if A >= 40.
                                        ; (Trigger "*** RANGE ERR".)
EECD: A8            tay
EECE: A5 C8         lda $c8             ; A = TXTNDX
EED0: 60            rts                 ; ("jmp $f828" in Integer BASIC;
EED1: EA            nop                 ; nop's replace the jump address.)
EED2: EA            nop

Patched $EEA6-$EED2: part 2 of HIMEM= handler, from basic.zip:

Code
; This routine, entered at $EEB6 from the patched HIMEM= handler, moves the
; program upward from the previous value of HIMEM to the new, higher value
; passed in $48,$49. Both HIMEM and $48,$49 are decremented as the move
; proceeds; it stops when HIMEM == PP, at which point the entire program has
; been moved and $48,$49 now has the new value for PP.
;
; The routine then proceeds to the final block.

        ; MOVELOOP:
EEA6: A5 4C         lda $4c
EEA8: D0 02         bne $eeac

EEAA: C6 4D         dec $4d

EEAC: C6 4C         dec $4c             ; Decrement HIMEM.
EEAE: A5 48         lda $48
EEB0: D0 02         bne $eeb4

EEB2: C6 49         dec $49

EEB4: C6 48         dec $48             ; Decrement $48,$49.

        ; Entry point from $EF93 in modified HIMEM= command handler:

EEB6: A0 00         ldy #$00            ; Y = 0
EEB8: B1 4C         lda ($4c), y
EEBA: 91 48         sta ($48), y        ; *($48,$49) = *HIMEM
EEBC: A5 CA         lda $ca
EEBE: C5 4C         cmp $4c
EEC0: A5 CB         lda $cb
EEC2: E5 4D         sbc $4d
EEC4: 90 E0         bcc $eea6           ; If PP < HIMEM branch to MOVELOOP
                                        ; (decrement pointers and repeat)

                                        ; If PP >= HIMEM:
EEC6: 4C 53 EE      jmp $ee53           ;     Jump to final block.


; ...Remnant of disabled VLIN statement's "AT" token handler:

EEC9: C9 28         cmp #$28
EECB: B0 9B         bcs $ee68

EECD: A8            tay
EECE: A5 C8         lda $c8
EED0: 60            rts
EED1: EA            nop
EED2: EA            nop

Original Apple $EE53-$EE62: OFF and (disabled) VTAB command handlers, from basica.zip:

Code
EE53: EA            nop


; OFF command handler:
;
; (OFF is undocumented, but it does work, just not very well. It was renamed
; to MAN in Apple II Integer BASIC.)

EE54: 46 F8         lsr $f8             ; Turn off AUTOFLAG.
EE56: 60            rts


; VTAB statement handler:
;
; (This is disabled both in the parser and here; it loads and checks its argument,
; stores it to $25 (CV), a zero-page variable used by the Apple II's VTAB Monitor
; routine, and then returns. The Integer BASIC version instead jumps to the VTAB
; routine at $FC22.)

EE57: 20 34 EE      jsr $ee34           ; Call GETBYTE (command argument -> A).
EE5A: C9 18         cmp #$18
EE5C: B0 0A         bcs $ee68           ; Branch if A >= 24.
                                        ; (Trigger "*** RANGE ERR".)

EE5E: 85 25         sta $25             ; CV = A
EE60: 60            rts                 ; ("jmp $fc22" in Integer BASIC;
EE61: EA            nop                 ; nop's replace the jump address.)
EE62: EA            nop

Patched $EE53-$EE62: part 3 of HIMEM= handler, from basic.zip:

Code
; This routine, jumped to from $EEC6 in the move-program block, is the
; modified HIMEM= handler's final phase. The program has been copied upward,
; and the new top of program is now in $48,$49. The new value for HIMEM is
; still present in ACC. All we need to do now is to reset the proper pointers,
; and we're done.

EE53: 8A            txa                 ; Save X in A.
EE54: A2 01         ldx #$01            ; X = 1

EE56: B4 CE         ldy $ce, x
EE58: 94 4C         sty $4c, x          ; HIMEM = ACC ("HIMEM=" argument)
EE5A: B4 48         ldy $48, x
EE5C: 94 CA         sty $ca, x          ; PP = $48,$49 (adjusted PP value)
EE5E: CA            dex
EE5F: F0 F5         beq $ee56

EE61: AA            tax                 ; Restore X from A.
EE62: 60            rts                 ; Return.

#109611 - 05/20/17 10:05 AM Re: apple1 basic.zip vs. basica.zip: which is Apple's? [Re: Dagarman]  
Joined: Jun 2003
Posts: 30
Colin Howell Offline
Member
Colin Howell  Offline
Member

Joined: Jun 2003
Posts: 30
Mountain View, CA
Originally Posted by Dagarman
Corey Cohen provided a copy of BASIC that he loaded from an original BASIC tape and recorded with an iRig from an original Apple I.
It matches the softlisted basica version in the 3 differing memory areas.

Here is a copy of the tape.

Thanks, I appreciate such rapid confirmation!

#109612 - 05/20/17 01:03 PM Re: apple1 basic.zip vs. basica.zip: which is Apple's? [Re: Colin Howell]  
Joined: Mar 2001
Posts: 15,753
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,753
USA
Awesome! When we get some Apple I specific documentation up I'd love to include this.

#109614 - 05/21/17 12:18 AM Re: apple1 basic.zip vs. basica.zip: which is Apple's? [Re: Colin Howell]  
Joined: Apr 2005
Posts: 530
Darkstar Offline
Senior Member
Darkstar  Offline
Senior Member

Joined: Apr 2005
Posts: 530
GERMANY
There's also Michael Steil's "all-in-one" 6502 BASIC source code here

But I'm sure almost everyone here knows about that already ;-)


Who's Online Now
1 registered members (Edstrom), 16 guests, and 4 spiders.
Key: Admin, Global Mod, Mod
Shout Box
Forum Statistics
Forums9
Topics8,436
Posts109,404
Members4,766
Most Online225
May 26th, 2014
Powered by UBB.threads™ PHP Forum Software 7.6.0
Page Time: 0.035s Queries: 15 (0.016s) Memory: 4.9955 MB (Peak: 5.1897 MB) Zlib enabled. Server Time: 2017-11-22 13:19:53 UTC