Welcome to the AppleWin wiki!
HGR
= HGR Y to Address =
Given:
y = abcd efgh (Range 0 .. 191 = $00 .. $BF)
Address of the scanline is calculated via:
---- ---- abcd efgh INPUT: Y
---- ---- ---- -fgh &7
---- -fgh ---- ---- * 0x100
+ ---f gh-- ---- ---- * 4
---- ---- abcd efgh INPUT: Y
---- ---- ---a bcde y/8
---- ---- ---- -cde & 7
---- ---- -cde ---- * 0x10
+ ---- --cd e--- ---- * 8
---- ---- abcd efgh INPUT: Y (64 = 2^6)
---- ---- ---- --ab y/64
---- ---- --ab ---- * 0x10
---- ---- -ab- ---- * 2
---- ---- ---a b--- y/64 * 8
+ ---- ---- -aba b--- y/64*0x28 See Note for alt. * 0x28
0PP- ---- 0000 0000 Graphics page, $20 or $40
= 0PPf ghcd eaba b000 Address
C code:
int HGR_y_to_address( int y ) {
return 0x2000 + (y&7)*0x400 + ((y/8)&7)*0x80 + (y/64)*0x28;
}
6502 code variation 1 (Original Applesoft)
GBASL EQU $26
GBASH EQU $27
HPAG EQU $E6 ; Used by Applesoft, 20 HGR1, 40 HGR2
ORG $F417
; Algorithm Y to HGR address
; INPUT: A = row (0 .. 191)
; The normal entry point is HPOSN $F411, A=row, Y,X=col
; F411: STA $E2
; F413: STX $E3
; F415: STY $E1
F417: Y2HGRAddr
F417: 48 PHA ; Y = abcdefgh
F418: 29 C0 AND #$C0 ; A = ab000000
F41A: 85 26 STA GBASL ;
F41C: 4A LSR ; A = 0ab00000
F41D: 4A LSR ; A = 00ab0000
F41E: 05 26 ORA GBASL ; = abab0000
F420: 85 26 STA GBASL
F422: 68 PLA ; C A GBASH GBASL
F423: 85 27 STA GBASH ; ? abcdefgh abcdefgh abab0000
F425: 0A ASL ; a bcdefgh0 abcdefgh abab0000
F426: 0A ASL ; b cdefgh00 abcdefgh abab0000
F427: 0A ASL ; c defgh000 abcdefgh abab0000
F428: 26 27 ROL GBASH ; a defgh000 bcdefghc abab0000
F42A: 0A ASL ; d efgh0000 bcdefghc abab0000
F42B: 26 27 ROL GBASH ; b efgh0000 cdefghcd abab0000
F42D: 0A ASL ; e fgh00000 cdefghcd abab0000
F42E: 66 26 ROR GBASL ; 0 fgh00000 cdefghcd eabab000
F430: A5 27 LDA GBASH ; 0 cdefghcd cdefghcd eabab000
F432: 29 1F AND #$1F ; 0 000fghcd cdefghcd eabab000
F434: 05 E6 ORA HPAG ; 0 pppfghcd cdefghcd eabab000
F436: 85 27 STA GBASH ; 0 pppfghcd pppfghcd eabab000
RTS
6502 code variation 2 (Woz's new version)
Woz Re-Codes Hi-Res Address Calculations Bob Sander-Cederlof In the October or November issue of the Washington Apple Pi newsletter, Rick Chapman wrote a review of various methods of calculating the hi-res base addresses. Steve Wozniak liked the article, and responded with a long "letter to the editor" in the December issue. Steve also presented a new version of the hi-res address calculator which is both shorter and faster. In fact, as far as I am aware, it is the fastest method ever, except for table-lookups.
In the September 1983 issue of Apple Assembly Line, I presented both the original Woz code and a shorter-faster version by Harry Cheung of Nigeria. Here are the specs:
Applesoft ROM version: 33 bytes, 61 cycles
Harry Cheung version: 25 bytes, 46 cycles
New Wozniak version: 26 bytes, 36 or 37 cycles
The byte counts do not include an RTS at the end of the code, nor do the times include a JSR-RTS. After all, if you are really working for speed you will put the code in its place, not make it a subroutine.
Woz's new version takes either 36 or 37 cycles, depending on the values for the first two bits of the line number. Remember that the line number can be any value from 0 to 191, or $00...$BF. That means the first two bits are either 00, 01, or 10. If you look at lines 1090-1120 below, you will see that the shortest path is for 00, taking both branches, giving a running time for the whole calculation of 36 cycles. If the first two bits are 01 or 10, one branch will be taken and the other not, making the total time 37 cycles. In Woz's letter he shortchanged himself, thinking possibly both branches might not be taken, giving a total running time of 38 cycles; this cannot happen with legal line numbers.
Line 1180 adds in either $10 or $20, depending on which hi-res page you are using. The Applesoft code here adds in a value of either $20 or $40, so if this version were to be inserted into Applesoft the generation of HPAG2 would have to be changed. No problem, and not likely anyway. By the way, if you are only using one specific hi-res page, you can change line 1180 to an immediate mode form, saving yet another cycle.
Here is Woz's new version, reformatted for the S-C Assembler and with some changes in comments:
1000 *SAVE S.NEW.WOZ.HIRES.CALC
1010 *--------------------------------
1020 GBASL .EQ $26
1030 GBASH .EQ $27
1040 HPAG2 .EQ $E6 Applesoft puts it here anyway.
1050 *--------------------------------
1060 CALC ASL A--BCDEFGH0
1070 TAX TAX...TXA could be TAY...TYA
1080 AND #$F0 A--BCDE0000
1090 BPL .1 B=0
1100 ORA #$05 A--BCDE0B0B
1110 .1 BCC .2 A-0
1120 ORA #$0A A--BCDEABAB
1130 .2 ASL B--CDEABAB0
1140 ASL C--DEABAB00
1150 STA GBASL
1160 TXA C--BCDEFGH0
1170 AND #$0E C--0000FGH0
1180 ADC HPAG2 O--OOxxFGH0
1190 * HPAG2 = $10 for base $2000, $20 for base $4000
1200 ASL GBASL D--00xxFGHC GBASL=EABAB000
1210 ROL 0--0xxFGHCD
1220 STA GBASH
1230 RTS
1240 *--------------------------------
6502 code variation 3 (lookup table)
Of course the table/array lookup is the fastest. Classic Space vs Speed trade-off.
y2hgrL EQU $1000
y2hgrH EQU $1100
ORG $0900
; Table Y to HGR address
; INPUT: Y = row (0 .. 191)
0900: B9 00 10 Y2HGRADR LDA y2hgrL, Y
0903: 85 26 STA GBASL
0905: B9 00 11 LDA y2hgrH, Y
0908: 44 E6 ORA HPAG ; #$20 for HGR1, #$40 for HGR2
090A: 85 27 STA GBASH
090C: 60 RTS
ORG $1000
1000: 00 00 00 00 00 00 00 00
1008: 80 80 80 80 80 80 80 80
1010: 00 00 00 00 00 00 00 00
1018: 80 80 80 80 80 80 80 80
1020: 00 00 00 00 00 00 00 00
1028: 80 80 80 80 80 80 80 80
1030: 00 00 00 00 00 00 00 00
1038: 80 80 80 80 80 80 80 80
1040: 28 28 28 28 28 28 28 28
1048: A8 A8 A8 A8 A8 A8 A8 A8
1050: 28 28 28 28 28 28 28 28
1058: A8 A8 A8 A8 A8 A8 A8 A8
1060: 28 28 28 28 28 28 28 28
1068: A8 A8 A8 A8 A8 A8 A8 A8
1070: 28 28 28 28 28 28 28 28
1078: A8 A8 A8 A8 A8 A8 A8 A8
1080: 50 50 50 50 50 50 50 50
1088: D0 D0 D0 D0 D0 D0 D0 D0
1090: 50 50 50 50 50 50 50 50
1098: D0 D0 D0 D0 D0 D0 D0 D0
10A0: 50 50 50 50 50 50 50 50
10A8: D0 D0 D0 D0 D0 D0 D0 D0
10B0: 50 50 50 50 50 50 50 50
10B8: D0 D0 D0 D0 D0 D0 D0 D0
ORG $1100
1100: 00 04 08 0C 10 14 18 1C
1108: 00 04 08 0C 10 14 18 1C
1110: 01 05 09 0D 11 15 19 1D
1118: 01 05 09 0D 11 15 19 1D
1120: 02 06 0A 0E 12 16 1A 1E
1128: 02 06 0A 0E 12 16 1A 1E
1130: 03 07 0B 0F 13 17 1B 1F
1138: 03 07 0B 0F 13 17 1B 1F
1140: 00 04 08 0C 10 14 18 1C
1148: 00 04 08 0C 10 14 18 1C
1150: 01 05 09 0D 11 15 19 1D
1158: 01 05 09 0D 11 15 19 1D
1160: 02 06 0A 0E 12 16 1A 1E
1168: 02 06 0A 0E 12 16 1A 1E
1170: 03 07 0B 0F 13 17 1B 1F
1178: 03 07 0B 0F 13 17 1B 1F
1180: 00 04 08 0C 10 14 18 1C
1188: 00 04 08 0C 10 14 18 1C
1190: 01 05 09 0D 11 15 19 1D
1198: 01 05 09 0D 11 15 19 1D
11A0: 02 06 0A 0E 12 16 1A 1E
11A8: 02 06 0A 0E 12 16 1A 1E
11B0: 03 07 0B 0F 13 17 1B 1F
11B8: 03 07 0B 0F 13 17 1B 1F
= HGR Address to Y =
0PPfghcdeabab000 ab
PPfghcdeabab0000 << 1
11000000 & 0xC0
0PPfghcdeabab000 cde
0PPfghcdeaba >> 4
0111000 & 0x38
0PPfghcdeabab000 fgh
0PPfgh >> 10
0111 & 7
C code:
y = ((address & 0x18) << 3) | ((address & 0x1c00) >> 10) | ((address & 0x380) >> 4);
int HGR_address_to_y( int address ) {
return ((address << 1) & 0xC0) // ab
| ((address >> 4) & 0x38) // cde
| ((address >> 10) & 0x07);// fgh
}
TEXT
Text Row to Address
Given:
y = 000a bcde (Range 0 .. 23 = $00 .. $17)
---- ---- 000a bcde INPUT: Y
000a bcde ---- ---- * 256
000a bcd0 ---- ---- & 0xFE
0000 abcd ---- ---- / 2
0000 00cd ---- ---- & 3
+ 0000 01cd ---- ---- | 4
---- ---- 000a bcde INPUT: Y
---- ---- 000a b000 & 0x18
---- ---- e00a b000 = temp
---- ---- 000a b000 & 18
---- ---0 00ab 0000 * 2
---- --00 0ab0 0000 * 2
+ ---- --00 eaba b000 | temp
= 0000 01cd eaba b000 Address
; Algorithm Y to TXT address
; INPUT: A = row
BASL EQU $28
BASH EQU $29
ORG $FBC1
FBC1: 48 577 BASCALC PHA ;CALC BASE ADR IN BASL,H
FBC2: 4A 578 LSR ; FOR GIVEN LINE NO
FBC3: 29 03 579 AND #$03 ; 0<=LINE NO.<=$17
FBC5: 09 04 580 ORA #$04 ;ARG=000ABCDE, GENERATE
FBC7: 85 29 581 STA BASH ; BASH=000001CD
FBC9: 68 582 PLA ; AND
FBCA: 29 18 583 AND #$18 ; BASL=EABAB000
FBCC: 90 02 584 BCC BSCLC2
FBCE: 69 7F 585 ADC #$7F
FBD0: 85 28 586 BSCLC2 STA BASL
FBD2: 0A 587 ASL
FBD3: 0A 588 ASL
FBD4: 05 28 589 ORA BASL
FBD6: 85 28 590 STA BASL
FBD8: 60 591 RTS
; Table Y to TXT address
; INPUT: Y = row
y2txtL EQU $1280
y2txtH EQU $1298
ORG $1200
1200: B9 80 12 Y2TXTADR LDA y2txtL, Y
1203: 85 28 STA BASL
1205: B9 98 12 LDA y2txtH, Y
1208: 85 29 STA BASH
120A: 60 RTS
ORG $1280
1280: 00 80 00 80 00 80 00 80 ; Rows 0 .. 7 ($00 .. $07)
1288: 28 A8 28 A8 28 A8 28 A8 ; Rows 8 ..15 ($08 .. $10)
1290: 50 D0 50 D0 50 D0 50 D0 ; Rows 16 ..23 ($10 .. $17)
1298: 04 04 05 05 06 06 07 07 ; Rows 0 .. 7 ($00 .. $07)
1298: 04 04 05 05 06 06 07 07 ; Rows 8 ..15 ($08 .. $10)
1298: 04 04 05 05 06 06 07 07 ; Rows 16 ..23 ($10 .. $17)
Text Address to Row
TODO!