Home

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: 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
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);

return ((address <<  1) & 0xC0) // ab
| ((address >>  4) & 0x38) // cde
| ((address >> 10) & 0x07);// fgh
}
``````

# TEXT

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)
``````