Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Apple II Graphics Programming (Assembly)

1,311 views
Skip to first unread message

cerebral_monkey

unread,
Jul 7, 2009, 7:40:04 PM7/7/09
to
Hello, I posted here a few months ago asking for help learning
assembly language on the Apple //c (under the handle tomatoes, though
I prefer this one, it is an anagram of my name!). I was hoping that I
might get a little bit more help, specifically where graphics
programming is concerned.

I found a cheetsheet from Beagle Bros that lists useful ROM subroutine
calls, one of these (at $F3F2) is purported to clear the high-
resolution screen that is currently being used. But when I try to use
it, I can't seem to get it to work.

Here is the code that I am trying:

ORG $1000

TXTCLR EQU $C050 ; text mode off (graphics on)
MIXCLR EQU $C052 ; mixed mode off
HISCR EQU $C054 ; use HIRES screen 1
HIRES EQU $C057 ; HIRES mode on
CLEAR EQU $F2F3

LDY #$00 ; set graphics modes
STY TXTCLR
STY MIXCLR
STY HIRES
STY HISCR
JSR CLEAR ; CLEAR the screen
TYA
BRK

Am I doing something wrong here? The screen is still filled with
random data after execution. (I wrote a subroutine to clear the
screen, but the built-in version is probably much faster)

I've got my mind set on re-creating pong, and I noticed that there
were some other useful-looking calls that I might be able to use,
including Hi-Res Colission-Check ($E6). Where might I find more on
these calls and how to use them?

If anyone might direct me to some more information about this, it
would be greatly appreciated! (I just ordered a book called "Assembly
Language for Applesoft Programmers" that should give me a little bit
more info, but I'm impatient, hah )

Michael J. Mahon

unread,
Jul 7, 2009, 8:27:55 PM7/7/09
to

Page zero location $E6 must be preset to the graphics page you
are clearing: $20 for HGR1 and $40 for HGR2.

$F2F3 clears the current page to black, but you can set the page
to any color by placing a "color byte" in the A register and calling
$F3F4, or by setting $1C to the desired color byte and calling $F3F6.

> I've got my mind set on re-creating pong, and I noticed that there
> were some other useful-looking calls that I might be able to use,

> including Hi-Res Collision-Check ($E6). Where might I find more on


> these calls and how to use them?

The collision counter is incremented when a DRAW or XDRAW changes a
screen 1 to a 0, so it will be greater than zero after the "draw" if
the shape "collided" with something non-black.

(I've frequently used it to "read" the hi-res screen a pixel at a time
by XDRAWing a single-pixel shape and checking the collision counter.)

> If anyone might direct me to some more information about this, it
> would be greatly appreciated! (I just ordered a book called "Assembly
> Language for Applesoft Programmers" that should give me a little bit
> more info, but I'm impatient, hah )

What you really want is "All About Applesoft" from Call-A.P.P.L.E.,
and a commented listing of the Applesoft ROMs is also very helpful.

I believe that both are available on the web, though I find myself using
the Applesoft disassembly produced by Sourcerer (on the back side of
Merlin 8) most often.

-michael

NadaNet 3.0 for Apple II parallel computing!
Home page: http://home.comcast.net/~mjmahon/

"The wastebasket is our most important design
tool--and it's seriously underused."

Polymorph

unread,
Jul 7, 2009, 8:45:06 PM7/7/09
to
On Jul 8, 10:27 am, "Michael J. Mahon" <mjma...@aol.com> wrote:
> cerebral_monkey wrote:

> > CLEAR  EQU     $F2F3

<snip>

> Page zero location $E6 must be preset to the graphics page you
> are clearing: $20 for HGR1 and $40 for HGR2.
>
> $F2F3 clears the current page to black, but you can set the page
> to any color by placing a "color byte" in the A register and calling
> $F3F4, or by setting $1C to the desired color byte and calling $F3F6.

I'm no assembly programmer, but looking at the Beagle chart (and A2
FAQ), it would seem you both have made the same typo - isn't the
correct address to call $F3F2, *not* $F2F3?

Cheers,
Mike

ict@ccess

unread,
Jul 8, 2009, 12:26:51 AM7/8/09
to
> I've got my mind set on re-creating pong, and I noticed that there
> were some other useful-looking calls that I might be able to use,
> including Hi-Res Colission-Check ($E6). Where might I find more on
> these calls and how to use them?
>
> If anyone might direct me to some more information about this, it
> would be greatly appreciated! (I just ordered a book called "Assembly
> Language for Applesoft Programmers" that should give me a little bit
> more info, but I'm impatient, hah )


I recommend doing a search for a book called "Hi-Res Graphics and
Animation using Assembly Language" by Leonard Malkin which also
touches on double Hi-Res for the Apple IIc. It pretty much covers all
the animation drawing routines and has some good routines that cover
counters and collision as well.

Someone may have it in .pdf format. If not, I may decide to sit down
and scan it sometime. All 313 pages. :)

Rob


Nick Westgate

unread,
Jul 8, 2009, 12:30:53 AM7/8/09
to cerebral_monkey
On Jul 8, 8:40 am, cerebral_monkey <berkley...@gmail.com> wrote:
> I've got my mind set on re-creating pong, and I noticed that there
> were some other useful-looking calls that I might be able to use,
> including Hi-Res Colission-Check ($E6). Where might I find more on
> these calls and how to use them?
>
> If anyone might direct me to some more information about this, it
> would be greatly appreciated! (I just ordered a book called "Assembly
> Language for Applesoft Programmers" that should give me a little bit
> more info, but I'm impatient, hah )

If you're more interested in learning assembly language I would steer
clear of using any routines in the ROM and write your own. They will
be faster and you will learn more about assembly language by doing so.
Of course studying the ROMs for coding tips and tricks is a good idea.

When I was a kid I started with the excellent Graph Paper articles:
http://www.atarimagazines.com/creative/index/index.php?author=David+Lubar

Only a few are able to be read there. I'd recommend "A bit of a shift"
and "The graph paper" (the final article). Hopefully someone has links
to the complete articles.

Cheers,
Nick.

Nick Westgate

unread,
Jul 8, 2009, 1:05:10 AM7/8/09
to
On Jul 8, 1:26 pm, "ict@ccess" <gids...@sasktel.net> wrote:
> I recommend doing a search for a book called "Hi-Res Graphics and
> Animation using Assembly Language" by Leonard Malkin which also
> touches on double Hi-Res for the Apple IIc.  It pretty much covers all
> the animation drawing routines and has some good routines that cover
> counters and collision as well.
>
> Someone may have it in .pdf format.  If not, I may decide to sit down
> and scan it sometime.  All 313 pages. :)
>
> Rob

Ooh! Yes please! :-D

Cheers,
Nick.

Michael J. Mahon

unread,
Jul 8, 2009, 4:07:42 AM7/8/09
to

You're absolutely right. I read the later entry points off the listing,
but copied the first from the question--they are all adjacent. ;-)

Michael J. Mahon

unread,
Jul 8, 2009, 4:13:44 AM7/8/09
to
Nick Westgate wrote:
> On Jul 8, 8:40 am, cerebral_monkey <berkley...@gmail.com> wrote:
>> I've got my mind set on re-creating pong, and I noticed that there
>> were some other useful-looking calls that I might be able to use,
>> including Hi-Res Colission-Check ($E6). Where might I find more on
>> these calls and how to use them?
>>
>> If anyone might direct me to some more information about this, it
>> would be greatly appreciated! (I just ordered a book called "Assembly
>> Language for Applesoft Programmers" that should give me a little bit
>> more info, but I'm impatient, hah )
>
> If you're more interested in learning assembly language I would steer
> clear of using any routines in the ROM and write your own. They will
> be faster and you will learn more about assembly language by doing so.
> Of course studying the ROMs for coding tips and tricks is a good idea.

And the "clear the hi-res page" routine is, in fact, one of the slower
Applesoft ROM routines!

The Monitor ROM ($F800..$FFFF) is by Woz and Allen Baum, and is a fine
tutorial in assembly language techniques. The Applesoft ROM, not so
much.

Polymorph

unread,
Jul 8, 2009, 5:54:34 AM7/8/09
to

I'm gonna go buy a lottery ticket now, 'cause its a rare day indeed
when I catch you out.... ;-)

Cheers,
Mike

Polymorph

unread,
Jul 8, 2009, 5:50:55 AM7/8/09
to
To: Michael J. Mahon

Michael J. Mahon wrote:
> Nick Westgate wrote:
>> On Jul 8, 8:40 am, cerebral_monkey <berkley...@gmail.com> wrote:
>>> I've got my mind set on re-creating pong, and I noticed that there
>>> were some other useful-looking calls that I might be able to use,
>>> including Hi-Res Colission-Check ($E6). Where might I find more on
>>> these calls and how to use them?
>>>
>>> If anyone might direct me to some more information about this, it
>>> would be greatly appreciated! (I just ordered a book called "Assembly
>>> Language for Applesoft Programmers" that should give me a little bit
>>> more info, but I'm impatient, hah )
>>
>> If you're more interested in learning assembly language I would steer
>> clear of using any routines in the ROM and write your own. They will
>> be faster and you will learn more about assembly language by doing so.
>> Of course studying the ROMs for coding tips and tricks is a good idea.
>
> And the "clear the hi-res page" routine is, in fact, one of the slower
> Applesoft ROM routines!
>
> The Monitor ROM ($F800..$FFFF) is by Woz and Allen Baum, and is a fine
> tutorial in assembly language techniques. The Applesoft ROM, not so
> much.
>

Hmmm.... Title fight between Woz & Microsoft: Microsoft is KO'ed in the
first 30 seconds of the first round... ;-)

Cheers,
Mike

paulrsm

unread,
Jul 8, 2009, 8:58:24 AM7/8/09
to
On Jul 8, 12:26 am, "ict@ccess" <gids...@sasktel.net> wrote:
> I recommend doing a search for a book called "Hi-Res Graphics and
> Animation using Assembly Language" by Leonard Malkin which also
> touches on double Hi-Res for the Apple IIc.  It pretty much covers all
> the animation drawing routines and has some good routines that cover
> counters and collision as well.

I have this book. The explanations are good but the code is mediocre.

--
Paul Santa Maria
Maumee, Ohio USA

paulrsm

unread,
Jul 8, 2009, 9:10:45 AM7/8/09
to
> > And the "clear the hi-res page" routine is, in fact, one of the slower
> > Applesoft ROM routines!
> > The Monitor ROM ($F800..$FFFF) is by Woz and Allen Baum, and is a fine
> > tutorial in assembly language techniques.  The Applesoft ROM, not so
> > much.
> Hmmm.... Title fight between Woz & Microsoft: Microsoft is KO'ed in the
> first 30 seconds of the first round...  ;-)

The ROM routines by Woz and Baum were written to optimize size, not
speed.

The Hi-Res routines in Applesoft were written by Woz. See the
Programmer's
Aid #1 manual for assembly source code.

paulrsm

unread,
Jul 8, 2009, 9:44:12 AM7/8/09
to
On Jul 7, 7:40 pm, cerebral_monkey <berkleycame...@gmail.com> wrote:
> Am I doing something wrong here? The screen is still filled with
> random data after execution. (I wrote a subroutine to clear the
> screen, but the built-in version is probably much faster)

My standard way of clearing the hi-res screen is:

LDA #0 ;FILL BYTE
LDY #PAGE ;PAGE=$20, $40, or $60
STY PTR+1
LDY #0 ;INIT INDEX
STY PTR
LDX #$20 ;PAGE COUNT
a STA (PTR),Y
INY
BNE a
INC PTR+1
DEX
BNE a
RTS

If I need speed, then I use

; clear hi-res page 1
LDA #0 ;FILL BYTE
LDY #0 ;INIT INDEX
a STA $2000,Y
STA $2100,Y
STA $2200,Y
STA $2300,Y
...
STA $3E00,Y
STA $3F00,Y
INY
BNE a
RTS

BLuRry

unread,
Jul 8, 2009, 11:14:18 AM7/8/09
to
> If I need speed, then I use
>
> ; clear hi-res page 1
>  LDA #0 ;FILL BYTE
>  LDY #0 ;INIT INDEX
> a STA $2000,Y
>  STA $2100,Y
>  STA $2200,Y
>  STA $2300,Y
>  ...
>  STA $3E00,Y
>  STA $3F00,Y
>  INY
>  BNE a
>  RTS
>
> --
> Paul Santa Maria
> Maumee, Ohio USA

Very nice unrolling, Paul! That must be pretty speedy! Is it
possible to avoid screen holes without losing too much performance?

-Brendan

Calibrator

unread,
Jul 8, 2009, 11:46:35 AM7/8/09
to
On 8 Jul., 17:14, BLuRry <brendan.rob...@gmail.com> wrote:
>
> Very nice unrolling, Paul!  That must be pretty speedy!  Is it
> possible to avoid screen holes without losing too much performance?

Insert "CPY #$F8" directly after the INY and you should be done.

The memory gain is negligible (unless you absolutely want to
preserve the screen holes) but it's infact a bit speedier!

While you need additional cycles for the comparison:

(CPY #)= 2 cycles x 248 runs = 496 cycles

you save more cycles because you avoid eight index runs:

(STA $aaaa,Y) = 5 cycles x 32 instructions x 8 runs = 1280 cycles
(INY) = 2 cycles x 8 runs = 16 cycles
(BNE with branch) = 3 cycles x 8 runs = 24 cycles
total = 1320

Cycles gained: 1320 - 496 = 824

Branches over page boundaries ignored in both cases and the
final BNE with no branch (2 cycles) happens in both variants.

bye
Marcus

ict@ccess

unread,
Jul 8, 2009, 12:35:57 PM7/8/09
to


The "CPY #F8" does not work because screen holes only happen only once
every $400 bytes so the program needs a little more coding. Screen
holes are from

$23F8 - $23FF
$27F8 - $27FF
$2BF8 - $2BFF
$2FF8 - $2FFF
$33F8 - $33FF
$37F8 - $37FF
$3BF8 - $3BFF
$3FF8 - $3FFF

here is a program that I use to save the screen holes

 LDY #PAGE ;PAGE=$20, $40, or $60
 STY PTR+1
 LDY #0

 STY PTR
 LDX #$20
a LDA #0
b STA (PTR),Y
 INY
 BNE b
 INC PTR+1
DEX
BEQ d
TXA
AND #3
CMP #3
BNE a
LDA #0
c STA (PTR),Y
INY
CPY #F8
BCC c
INC PTR+1
DEX
 BNE b
d  RTS

As you can see, only the one page out of 4 would get slowed down due
to the comparison.

Rob

ict@ccess

unread,
Jul 8, 2009, 12:48:57 PM7/8/09
to
If you were following the code, you would see the errors. I was
trying to do it from the top of my head

Here is the corrected version

 LDY #PAGE ;PAGE=$20, $40, or $60
STY PTR+1
LDY #0
STY PTR

LDX #$1F


a LDA #0
b STA (PTR),Y
 INY
 BNE b
 INC PTR+1
DEX

TXA
AND #3
CMP #3
BNE a
LDA #0
c STA (PTR),Y
INY
CPY #F8
BCC c
INC PTR+1
DEX

 BPL b
d  RTS


Mark Calderbank

unread,
Jul 8, 2009, 12:38:04 PM7/8/09
to
Calibrator <calib...@freenet.de> wrote:
> On 8 Jul., 17:14, BLuRry <brendan.rob...@gmail.com> wrote:
>>
>> Very nice unrolling, Paul! �That must be pretty speedy! �Is it
>> possible to avoid screen holes without losing too much performance?
>
> Insert "CPY #$F8" directly after the INY and you should be done.

I'm not sure about this. Aren't there screen holes at 78-7F as well
as F8-FF? Assuming my memory's right, I can come up with three options.

If you have tons of code space, you can do the thoughtless thing
and just double the loop length:

LDA #0
LDY #$77
a STA $2000,Y
STA $2080,Y
...
STA $3F00,Y
STA $3F80,Y
DEY
BPL a

Or you can do something like what Calibrator said but skip over the
middle hole along the way:

LDA #0
LDY #0
a STA $2000,Y
...
STA $3F00,Y
INY
CPY #$F8
BEQ end
CPY #$78
BNE a
LDY #$80
BNE a
end

Or involve the X register and run the same loop twice with different
index values but the same exit condition:

LDA #0
LDY #$77
b LDX #$77


a STA $2000,Y
STA $2100,Y

...
STA $3F00,Y
DEY
DEX
BPL a
CPY #$7F
BEQ end
LDY #$F7
BNE b
end

Toinet

unread,
Jul 8, 2009, 1:21:12 PM7/8/09
to
Hi All,

Why do you want to preserve the different screen holes of the HGR
screens?

I understand that when you deal with the text screen as useful data is
recorded there but for high resolution pages where you will probably
use page flipping, sprites, page erasing, etc. then speed is required
and Paul's second algorithm is fine.

If you want to save room, use the routine in ROM. If you want speed,
forget about the screen holes.

antoine

Calibrator

unread,
Jul 8, 2009, 3:14:45 PM7/8/09
to
On 8 Jul., 18:38, Mark Calderbank <nos...@test.com> wrote:
>
> I'm not sure about this. Aren't there screen holes at 78-7F as well
> as F8-FF?

According to the Apple IIe TechNote #10 you are right!
This TN handles the IIe-card for the Mac LC and I quote:

---
Notes:
1. The "Screen-Hole" areas in the above address ranges do
not trap.
These are the $xx78-7F and $xxF8-FF address ranges in the
display areas.
---

This makes sense as
- 240 bytes of each page x 32 pages = 7680 bytes
and
- 40 bytes per hires-line x 192 lines = 7680 bytes!


> Assuming my memory's right, I can come up with three options.
>
> If you have tons of code space, you can do the thoughtless thing
> and just double the loop length:
>
> LDA #0
> LDY #$77

> a STA $2000,Y (5)
> STA $2080,Y (5)
> ...
> STA $3F00,Y (5)
> STA $3F80,Y (5)

> DEY (2)
> BPL a (2/3)

You'd need a branch over a "JMP a" combo at the end as the
unrolled loop would be larger than the branch range...
(64 STA instructions with 3 bytes each = 192 bytes)

About 39600 cycles in total with a JMP and not counting
the register setup at the beginning of the routine - but about
200 bytes of code (400 bytes if you need both hires pages)...


> Or you can do something like what Calibrator said but skip
> over the middle hole along the way:

Sounds interesting!

> LDA #0
> LDY #0
> a STA $2000,Y (5)
> ...
> STA $3F00,Y (5)

> INY (2)
> CPY #$F8 (2)
> BEQ end (2/3)
> CPY #$78 (2)
> BNE a (2/3)
> LDY #$80 (2)
> BNE a (2/3)
> end

The 32 STAs run effectively 240 times x 5 cycles = 38400.
Add to that the stuff beginning with the INY and you'll get:
1 x 7 cycles ($F8 condition)
1 x 15 cycles ($78 condition)
238 x 11 cycles (first BNE successful)
= 2640 cycles
Which results in a total of 41040 cycles.

(I'm probably wrong with the loops but it should be close
enough ;-)

Paul's "standard unrolled version" uses a total of 42239 cycles,
though, as the loop runs 256 times.

With my $F8 check (which still fills about half the holes) it
would need about 40919 cycles...


> Or involve the X register and run the same loop twice with different
> index values but the same exit condition:
>
> LDA #0
> LDY #$77

> b LDX #$77

> a STA $2000,Y
> STA $2100,Y
> ...
> STA $3F00,Y

> DEY (2)
> DEX (2)
> BPL a (2/3)

> CPY #$7F (2)
> BEQ end (2/3)
> LDY #$F7 (2)
> BNE b (always 3)

> end

I hate cycle counting in nested loops - especially when
decrementing! ;-)

The a-loop runs 240 times = 38400+1679 = 40079
Special case #1 (Y=$7F) = +5 cycles (once)
Special case #2 (Y=$FF after DEY) = +11 cycles (once)
= total 40095 cycles (I hope...)

About 2000 cycles faster than Paul's routine (5%) - not very
eye-friendly but perhaps the best trade-off, isn't it?

bye
Marcus

Calibrator

unread,
Jul 8, 2009, 3:32:36 PM7/8/09
to
On 8 Jul., 19:21, Toinet <antoine.vig...@laposte.net> wrote:
>
> Why do you want to preserve the different screen holes of the HGR
> screens?

I would do it for speed reasons (see my answer to Mark) but
Rob (ict@ccess) apparently uses them for embedded code.
See this thread:
http://groups.google.com/group/comp.sys.apple2/browse_frm/thread/6764c2d36dd29d52#

> I understand that when you deal with the text screen as useful data is
> recorded there but for high resolution pages where you will probably
> use page flipping, sprites, page erasing, etc. then speed is required
> and Paul's second algorithm is fine.

If speed is very important you would use a line table anyway
and except for the page erasing I don't see why one would
access the screen holes with a sprite routine (or anything
else using the line table) at all.

> If you want to save room, use the routine in ROM. If you want speed,
> forget about the screen holes.

It's always a trade-off of course but if speed is paramount
I claim that bytes written to screen holes are wasted cycles.

bye
Marcus

Mark Calderbank

unread,
Jul 8, 2009, 7:17:37 PM7/8/09
to
Calibrator <calib...@freenet.de> wrote:
> This makes sense as
> - 240 bytes of each page x 32 pages = 7680 bytes
> and
> - 40 bytes per hires-line x 192 lines = 7680 bytes!

Yes, I thought to do a similar check after my post, namely:
40 x 192 = 7680 for the graphics
64 x 8 = 512 for the holes
Total = 8192: check!

> You'd need a branch over a "JMP a" combo at the end as the
> unrolled loop would be larger than the branch range...
> (64 STA instructions with 3 bytes each = 192 bytes)

Good point. I did say the method was thoughtless :-)

>> Or you can do something like what Calibrator said but skip
>> over the middle hole along the way:
>

> Which results in a total of 41040 cycles.
>

> Paul's "standard unrolled version" uses a total of 42239 cycles,
> though, as the loop runs 256 times.
>
> With my $F8 check (which still fills about half the holes) it
> would need about 40919 cycles...

I wasn't approaching this from the angle of skipping holes to improve
speed, but as a way of doing a fast clear while preserving the screen
holes in case they were being used. Just a silly exercise really.
So I'm not too surprised that this method turns out slower.

>> Or involve the X register and run the same loop twice with different
>> index values but the same exit condition:
>

> The a-loop runs 240 times = 38400+1679 = 40079
> Special case #1 (Y=$7F) = +5 cycles (once)
> Special case #2 (Y=$FF after DEY) = +11 cycles (once)
> = total 40095 cycles (I hope...)
>
> About 2000 cycles faster than Paul's routine (5%) - not very
> eye-friendly but perhaps the best trade-off, isn't it?

Ah, so this is actually quicker! I've never tried it so I have no idea
how it performs visually.

Thanks for doing the cycle counts!

Mark

Polymorph

unread,
Jul 8, 2009, 7:24:25 PM7/8/09
to

It seems I incorrectly assumed that Microsoft had written the
Applesoft routines, my bad. Thanks for setting me straight. It must be
my inner desire to blame Microsoft for everything bad in this
world.. ;-)

Cheers,
Mike

Calibrator

unread,
Jul 8, 2009, 11:25:09 PM7/8/09
to
On 9 Jul., 01:17, Mark Calderbank <nos...@test.com> wrote:

> Calibrator <calibra...@freenet.de> wrote:
> >
> > About 2000 cycles faster than Paul's routine (5%) - not very
> > eye-friendly but perhaps the best trade-off, isn't it?
>
> Ah, so this is actually quicker! I've never tried it so I have no idea
> how it performs visually.

They are all "ugly" IMHO as they aren't working the screen line
by line. Totally irrelevant if you use both pages and draw on the
invisible page, though.

With "eye-friendly" I meant the source code itself ;-)

bye
Marcus

Michael J. Mahon

unread,
Jul 9, 2009, 4:23:10 AM7/9/09
to

Actually, Microsoft did write Applesoft--with the exception of a
few Apple II specials, like lo- and hi-res graphics, paddles, etc.

The Applesoft interpreter is a bit uneven in its quality. Some
tradeoffs seem to have been carefully thought out, but parts of
it look like a hurried conversion from another microprocessor.

My guess is that the programmer was not very familiar with
6502 coding techniques going into the project...a situation
that was quite common in the early days.

Michael J. Mahon

unread,
Jul 9, 2009, 4:41:12 AM7/9/09
to

The routine in the Applesoft ROM can be used to clear any screen to
any "color" (including some striped/dithered patterns). To support
this it complements the low 7 bits of A on each horizontally adjacent
byte to preserve the "color meanings" for both even and odd bytes.

And it does the complementing in a *subroutine* instead of in-line--
a clear case of optimizing for space regardless of speed.

It's also interesting that the capability of "clearing" a screen to
a color other than Black1 (hi-bit off) is not used in Applesoft!

This suggests to me that the incorporation of Woz's Programmer's Aid #1
hi-res routines was done not by Woz, but by some delegate, maybe even
a Microsoft employee. ;-)

Polymorph

unread,
Jul 9, 2009, 5:56:25 AM7/9/09
to
To: Michael J. Mahon
Michael J. Mahon wrote:


Aha! So my title fight metaphor earlier in this thread may still be
valid! I knew it!! ;-)

Cheers,
Mike

paulrsm

unread,
Jul 9, 2009, 8:40:02 AM7/9/09
to
On Jul 8, 11:25 pm, Calibrator <calibra...@freenet.de> wrote:
> On 9 Jul., 01:17, Mark Calderbank <nos...@test.com> wrote:
> > I've never tried it so I have no idea how it performs visually.
> They are all "ugly" IMHO as they aren't working the screen line
> by line.

A very different visual effect can be achieved by replacing
the single INY with three INY instructions. This tweak is
courtesy of Bruce Artwick (the flight simulator guy).

lyricalnanoha

unread,
Jul 9, 2009, 9:46:29 AM7/9/09
to

On Thu, 9 Jul 2009, Michael J. Mahon wrote:

> The Applesoft interpreter is a bit uneven in its quality. Some
> tradeoffs seem to have been carefully thought out, but parts of
> it look like a hurried conversion from another microprocessor.

It was... it was ported over from the Z80.

-uso.

Michael J. Mahon

unread,
Jul 9, 2009, 12:10:19 PM7/9/09
to

Or perhaps even the 8080...but some ports are done with a much more
subtle adaptation to the target architecture. In the case of 6502
Microsoft BASIC, it seems that it was more important that the port
be completed quickly.

It's interesting to consider the "path not taken", which would
have been Woz completing the integration of floating-point into
Integer BASIC.

(Of course, this would have resulted in Apple BASIC being quite
different from most micro BASICs.)

lyricalnanoha

unread,
Jul 9, 2009, 2:00:15 PM7/9/09
to

On Thu, 9 Jul 2009, Michael J. Mahon wrote:

> lyricalnanoha wrote:
>>
>>
>> On Thu, 9 Jul 2009, Michael J. Mahon wrote:
>>
>>> The Applesoft interpreter is a bit uneven in its quality. Some
>>> tradeoffs seem to have been carefully thought out, but parts of
>>> it look like a hurried conversion from another microprocessor.
>>
>> It was... it was ported over from the Z80.
>
> Or perhaps even the 8080...but some ports are done with a much more
> subtle adaptation to the target architecture. In the case of 6502
> Microsoft BASIC, it seems that it was more important that the port
> be completed quickly.
>
> It's interesting to consider the "path not taken", which would
> have been Woz completing the integration of floating-point into
> Integer BASIC.
>
> (Of course, this would have resulted in Apple BASIC being quite
> different from most micro BASICs.)

And more like Atari BASIC, not? IIRC, that was done by the DOS 3.1
people.

-uso.

jamesiw...@gmail.com

unread,
Oct 19, 2015, 10:50:09 PM10/19/15
to
I know this is an old thread, but I just thought I'd post my solution to this problem, in case anyone would like to see it.

I figured out how to do this on my own just a couple of days ago.
The following code works in the Merlin assembler, and may have to be modified if someone is using a different assembler:



ORG $300
START LDA #$3F
LDX #0
STA $6001
CLEAR1 LDA #$FF
CLEAR2 STA $6000
LDY #0
LDA $6000
STA $CE
LDA $6001
STA $CF
LDA #0
STA ($CE,X)
DEC $6000 #1
LDA $6000
CMP #$FF
BNE CLEAR2
STA $6000
DEC $6001 #1
LDA $6001
CMP #$19
BNE CLEAR1
LDA $C050
LDA $C052
LDA $C054
LDA $C057
LDA $C01D
DONE RTS


This is a sufficient speed for clearing the screen at the beginning of a game, as it's only about a 1/2 - 1 second wait. I programmed the switching to graphics mode to go AFTER the HGR page 1 is cleared (the lines after BNE CLEAR1) , so you don't see it load with stripes and watch the stripes disappear. This clears it beforehand, so the user just sees a blank screen when the program goes into graphics mode.

If you really want to program hi-resolution graphics, you should really understand WHY this works, because if you don't even understand how to clear the screen, you surely won't be able to program a high-speed animation game on the Apple II, where sprites are moving all over the screen.

I'm basically loading memory locations $6000 - $6001 with the final hexadecimal address on the memory map, $3FFF. These addresses are stored backwards, because the Apple II reads such addresses backwards. So, $6000 contains $FF and $6001 contains $3F.

The program loops from $3FFF down to $19FF.
When it sees the $19 from $19FF, it knows it has gone outside of the bounds of the high resolution page, and thus the looping ends.

For each iteration, from $3FFF all the way down to $2000, a value of $00 is stored in each byte. It HAS TO jump down 1 byte at a time. So it will go from $3FFF to $3FFE to $3FFD, etc.. If you jump down by every $100 (256), that is not 1 byte, that is 256 bytes. In that case, you would not clear the whole screen.

STA ($CE,X) is the command to store the value of the Accumulator (0) into the location that $CE-$CF point to. So it uses a pointer to the current high-resolution byte, and stores in the location that $CE-$CF points to. $CE and $CF store the memory location backwards (that's how pointers work in Apple II assembly), so $3FFF would be stored as $FF in $CE and $3F in $CF. The X is just a dummy offset (in this case), it is set to 0 so it stores in the exact location indicated by $CE and $CF. If it were set to 1, then it would store the value in the address indicated by the pointer + 1 byte. So if $CE and $CF held the value $3FFF, then it would store the value in memory location $4000 if X were 1. But this version doesn't use the offset, even though it is part of the syntax.

On Tuesday, July 7, 2009 at 7:40:04 PM UTC-4, cerebral_monkey wrote:
> Hello, I posted here a few months ago asking for help learning
> assembly language on the Apple //c (under the handle tomatoes, though
> I prefer this one, it is an anagram of my name!). I was hoping that I
> might get a little bit more help, specifically where graphics
> programming is concerned.
>
> I found a cheetsheet from Beagle Bros that lists useful ROM subroutine
> calls, one of these (at $F3F2) is purported to clear the high-
> resolution screen that is currently being used. But when I try to use
> it, I can't seem to get it to work.
>
> Here is the code that I am trying:
>
> ORG $1000
>
> TXTCLR EQU $C050 ; text mode off (graphics on)
> MIXCLR EQU $C052 ; mixed mode off
> HISCR EQU $C054 ; use HIRES screen 1
> HIRES EQU $C057 ; HIRES mode on
> CLEAR EQU $F2F3
>
> LDY #$00 ; set graphics modes
> STY TXTCLR
> STY MIXCLR
> STY HIRES
> STY HISCR
> JSR CLEAR ; CLEAR the screen
> TYA
> BRK
>
> Am I doing something wrong here? The screen is still filled with
> random data after execution. (I wrote a subroutine to clear the
> screen, but the built-in version is probably much faster)
>

John Brooks

unread,
Oct 19, 2015, 11:39:22 PM10/19/15
to
Nice job getting your 6502 program working and clearing the hires screen.

A few things I noticed looking at your program:

1) You are using the addressing mode ($CE,X) which is really designed for arrays of pointers. A more efficient addressing mode is $2000,x or ($CE),y.

2) The 6502 is doing a lot of extra work copying your memory ptr from $6000/$6001 to $CE/$CF. If you keep your ptr always in $CE/$CF, it really simplify and speed up your routine.

3) Since you are working with hexadecimal addresses, the last byte past your screen clear will be $1FFF rather than $19FF.

Below is a version of the clear which uses ($CE),y. By using a more effective addressing mode and removing the ptr copies, it should run much faster and may show you some new techniques.

org $300
ldx #$3f
lda #0
sta $ce
tay
Clear1 stx $cf
Clear2 dey
sta ($ce),y
bne Clear2
dex
cpx #$1f
bcs Clear1
lda $c050
lda $c052
lda $c054
lda $c057
lda $c01d
rts

Happy coding!
-JB

awanderin

unread,
Oct 20, 2015, 12:56:47 AM10/20/15
to
You'll want to change the "bcs" to 'bne' otherwise, the code will clear
memory from $1f00-$1fff.

> lda $c050
> lda $c052
> lda $c054
> lda $c057
> lda $c01d
> rts
>
> Happy coding!
> -JB

--
--
Jerry awanderin at gmail dot com

fadden

unread,
Oct 20, 2015, 12:22:53 PM10/20/15
to
On Monday, October 19, 2015 at 7:50:09 PM UTC-7, jamesiw...@gmail.com wrote:
> I know this is an old thread, but I just thought I'd post my solution to this problem, in case anyone would like to see it.

Since anything worth doing is worth overdoing...

Discussion:
https://github.com/fadden/fdraw/blob/master/docs/manual.md#notes

Screen clear code, written two different ways (size vs. speed):
https://github.com/fadden/fdraw/blob/master/FDRAW.S#L271

The hi-res screen is a quirky beast... which is what makes it so much fun to play with.

It's always fun to solve something then see how other people have solved it. Having gone through the process yourself, you appreciate the subtleties in the other solutions. For example: nice job switching the graphics screen on *after* the clear -- looks much better that way.

jamesiw...@gmail.com

unread,
Oct 20, 2015, 8:57:01 PM10/20/15
to
On Monday, October 19, 2015 at 11:39:22 PM UTC-4, John Brooks wrote:

> Nice job getting your 6502 program working and clearing the hires screen.
>

Thanks.

> A few things I noticed looking at your program:
>
> 1) You are using the addressing mode ($CE,X) which is really designed for arrays of pointers. A more efficient addressing mode is $2000,x or ($CE),y.
>

Thanks for letting me know, I did not know that.

> 2) The 6502 is doing a lot of extra work copying your memory ptr from $6000/$6001 to $CE/$CF. If you keep your ptr always in $CE/$CF, it really simplify and speed up your routine.
>

Yeah, I put it in $6000 and $6001 because I was planning on going by a model when I was programming a full game, where there wouldn't be enough zero page memory to hold the addresses of all of the rows on the high resolution map. But for this small program, that would be better.

> 3) Since you are working with hexadecimal addresses, the last byte past your screen clear will be $1FFF rather than $19FF.
>

Arrggh! I don't know why I didn't catch that. Thanks for pointing that out. I know how to count in hexadecimal, that was a careless mistake.

> Below is a version of the clear which uses ($CE),y. By using a more effective addressing mode and removing the ptr copies, it should run much faster and may show you some new techniques.
>
> org $300
> ldx #$3f
> lda #0
> sta $ce
> tay
> Clear1 stx $cf
> Clear2 dey
> sta ($ce),y
> bne Clear2
> dex
> cpx #$1f
> bcs Clear1
> lda $c050
> lda $c052
> lda $c054
> lda $c057
> lda $c01d
> rts
>
> Happy coding!
> -JB

Thanks!

jamesiw...@gmail.com

unread,
Oct 20, 2015, 9:12:09 PM10/20/15
to
On Tuesday, October 20, 2015 at 12:56:47 AM UTC-4, awanderin wrote:
> John Brooks <jbr...@blueshiftinc.com> writes:
>
> > On Monday, October 19, 2015 at 7:50:09 PM UTC-7, jamesiw...@gmail.com wrote:
> >
> > org $300
> > ldx #$3f
> > lda #0
> > sta $ce
> > tay
> > Clear1 stx $cf
> > Clear2 dey
> > sta ($ce),y
> > bne Clear2
> > dex
> > cpx #$1f
> > bcs Clear1
>
> You'll want to change the "bcs" to 'bne' otherwise, the code will clear
> memory from $1f00-$1fff.
>

I did a test to see if you are correct. First of all, I had CMP #$19, not CPX #$1F. My mistake was to use #$19 instead of #$1F. So in my test I replaced my CMP #$19 with CMP #$1f. Then I re-compiled, saved the source, and saved the object code. (I have not yet modified it according to John Brooks' improvements.) Before I ran the program, the value of the address $1FFD was $FF. ($1FFE and $1FFF were $00 before the test) After running it, it was still $FF.

The comparison operator compares the higher two digits of the address to #$1F by subtracting $1F from the value of the accumulator, to see if the counting has gone below $2000. If the result of the subtraction is 0, it means that the value of the accumulator is $1F. That happens when the address is $1FFF, exactly 1 below $2000, because it wouldn't have passed the last branch if the lower 2 digits of the address to be cleared weren't $FF. So, if the comparison is not equal to 0, i.e. the accumulator is not equal to $1F and we haven't reached $1FFF, then it branches to continue the countdown. If the result is equal to zero, it does not branch, the screen has been cleared, and the program continues on to switch to graphics mode.

jamesiw...@gmail.com

unread,
Oct 20, 2015, 9:17:49 PM10/20/15
to
On Tuesday, October 20, 2015 at 12:22:53 PM UTC-4, fadden wrote:

> The hi-res screen is a quirky beast... which is what makes it so much fun to play with.
>

I agree completely.. With both of those statements.
If programming Apple II hi resolution were as easy as programming 2D animation in newer platforms, I would be using the newer platforms, simply because the graphical capabilities of modern computers are so much better. The whole fun of programming Apple II hi resolution in Assembly language is the challenge. Sure, I could still program assembly language graphics in Mode 13h, but that is not nearly as challenging as programming hi res on an Apple II.

> It's always fun to solve something then see how other people have solved > > it.
> Having gone through the process yourself, you appreciate the subtleties in > > the other solutions. For example: nice job switching the graphics
> screen on
> *after* the clear -- looks much better that way.

Thanks!

jamesiw...@gmail.com

unread,
Oct 20, 2015, 9:21:00 PM10/20/15
to

> > 2) The 6502 is doing a lot of extra work copying your memory ptr from $6000/$6001 to $CE/$CF. If you keep your ptr always in $CE/$CF, it really simplify and speed up your routine.
> >
>
> Yeah, I put it in $6000 and $6001 because I was planning on going by a > > > model when I was programming a full game, where there wouldn't be enough > > zero page memory to hold the addresses of all of the rows on the high > > > resolution map. But for this small program, that would be better.
>

Oh, not to mention that even in a complete game, for clearing the screen in the beginning, storing the values in $6000 and $6001 would be completely pointless, a fact that I overlooked.

awanderin

unread,
Oct 21, 2015, 12:07:19 AM10/21/15
to
Try this in the Apple II monitor:
1F00:FF
1F01<1F00.3FFEM this clears 1F00..3FFF to FFs
1F00.201F
300G C051
1F00.201F

1F00..3FFF are cleared to zeros.

CPX #nn subtracts nn from the X-register, discarding the result, but
setting the C-flag if there is no borrow, that is, if X >= nn. It also
sets the Z flag if X == nn.

jamesiw...@gmail.com

unread,
Oct 21, 2015, 12:42:35 AM10/21/15
to

> > 2) The 6502 is doing a lot of extra work copying your memory ptr from $6000/$6001 to $CE/$CF. If you keep your ptr always in $CE/$CF, it really simplify and speed up your routine.
> >
>
> Yeah, I put it in $6000 and $6001 because I was planning on going by a model
> when I was programming a full game, where there wouldn't be enough zero page
> memory to hold the addresses of all of the rows on the high resolution map.
> But for this small program, that would be better.
>

Actually, even in the model of a game that I had in mind, the values of the lookup table of course wouldn't change. So the only similarity between my clear screen and the game model I had in mind was that I was storing screen addresses somewhere other than zero page memory. For some reason, that single similarity was enough for me to make the last statement I did, which I should have thought out more before posting.

jamesiw...@gmail.com

unread,
Oct 21, 2015, 1:11:38 AM10/21/15
to
So you were talking about the modified code. My code originally said BNE, and my code didn't clear below $2000 after I changed $19 to $1F in the code that I posted. I was just in a hurry and missed the fact that you were talking about the modified code and not my original code. My original code would clear down to $1A00. With $1F instead of $19 it would clear down to $2000. And, of course, I should use zero page only for the countdown and scrap storing the countdown values in $6000 and $6001 and use (address),Y instead of (address,X)
0 new messages