Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.sys.apple2.programmer > #4656 > unrolled thread
| Started by | Masood <masood@masoodkamandy.com> |
|---|---|
| First post | 2018-07-29 23:08 -0700 |
| Last post | 2018-08-02 15:06 -0700 |
| Articles | 7 — 4 participants |
Back to article view | Back to comp.sys.apple2.programmer
Lookup Table ca65 Masood <masood@masoodkamandy.com> - 2018-07-29 23:08 -0700
Re: Lookup Table ca65 MG <*@guidero.us> - 2018-07-30 07:20 -0700
Re: Lookup Table ca65 Masood <masood@masoodkamandy.com> - 2018-07-30 08:35 -0700
Re: Lookup Table ca65 David Schmidt <schmidtd@my-deja.com> - 2018-07-30 13:21 -0400
Re: Lookup Table ca65 Masood <masood@masoodkamandy.com> - 2018-08-01 16:38 -0700
Re: Lookup Table ca65 Michael J. Mahon <mjmahon@aol.com> - 2018-08-01 18:47 -0500
Re: Lookup Table ca65 MG <*@guidero.us> - 2018-08-02 15:06 -0700
| From | Masood <masood@masoodkamandy.com> |
|---|---|
| Date | 2018-07-29 23:08 -0700 |
| Subject | Lookup Table ca65 |
| Message-ID | <c5c71c33-b4f8-4917-87bb-ee0b29e8d2e4@googlegroups.com> |
Hello, I am learning 6502 assembly for my Apple IIc Plus, using Xcode, ca65, and Quinn Dunki/Jeremy Rand's Apple2BuildPipeline: https://github.com/jeremysrand/Apple2BuildPipeline/ Working with AppleSoft routines has been fun, but I'd like to move into creating my own plot routine in assembly. I'd like to create a lookup routine that calculates the base address of a pixel in memory. I've found this lookup table on the AppleWin Wiki, which I'd like to repurpose for use in ca65: https://github.com/AppleWin/AppleWin/wiki It was designed for assemblers that do not create relocatable code. This is where I've hit a wall. I don't understand how to translate the ORG directive for use with ca65 by creating a .segment. I did find this link, which explains it, but I can't seem to understand how to make it work: https://github.com/cc65/wiki/wiki/The-.ORG-directive I think problem is my lack of understanding of how a linker works, and how I would manipulate the config file. Does anyone have any resources, best practices, or sample code that might explain what a linker is and how a lookup table can be created in ca65? Thank you. Masood
[toc] | [next] | [standalone]
| From | MG <*@guidero.us> |
|---|---|
| Date | 2018-07-30 07:20 -0700 |
| Message-ID | <a8789e60-2c67-47a4-b69c-27939b57a206@googlegroups.com> |
| In reply to | #4656 |
On Sunday, July 29, 2018 at 11:08:31 PM UTC-7, Masood wrote:
> Hello,
>
> I am learning 6502 assembly for my Apple IIc Plus, using Xcode, ca65, and Quinn Dunki/Jeremy Rand's Apple2BuildPipeline:
> https://github.com/jeremysrand/Apple2BuildPipeline/
>
> Working with AppleSoft routines has been fun, but I'd like to move into creating my own plot routine in assembly. I'd like to create a lookup routine that calculates the base address of a pixel in memory.
>
> I've found this lookup table on the AppleWin Wiki, which I'd like to repurpose for use in ca65:
> https://github.com/AppleWin/AppleWin/wiki
>
> It was designed for assemblers that do not create relocatable code.
>
> This is where I've hit a wall. I don't understand how to translate the ORG directive for use with ca65 by creating a .segment. I did find this link, which explains it, but I can't seem to understand how to make it work:
> https://github.com/cc65/wiki/wiki/The-.ORG-directive
>
> I think problem is my lack of understanding of how a linker works, and how I would manipulate the config file.
>
> Does anyone have any resources, best practices, or sample code that might explain what a linker is and how a lookup table can be created in ca65?
>
> Thank you.
>
> Masood
There is nothing stopping you from doing it the "traditional" way in ca65 with absolute code. That being said, the "ca65" way is something like this:
------ linker configuration
MEMORY {
BIN: start = $900, size = $1700;
}
SEGMENTS {
code: load = BIN;
y2hgrL: load = BIN, define = yes, align = $100;
y2hgrH: load = BIN, define = yes, align = $100;
}
------ code
GBASL = $26
GBASH = $27
HPAG = $E6 ; Used by Applesoft, 20 HGR1, 40 HGR2
.import __y2hgrL_LOAD__
.import __y2hgrH_LOAD__
.segment "code"
; Table Y to HGR address
; INPUT: Y = row (0 .. 191)
Y2HGRADR:
LDA __y2hgrL_LOAD__,Y
STA GBASL
LDA __y2hgrH_LOAD__,Y
ORA HPAG ; #$20 for HGR1, #$40 for HGR2
STA GBASH
RTS
.segment "y2hgrL"
.align $100
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.segment "y2hgrH"
.align $100
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
MG
[toc] | [prev] | [next] | [standalone]
| From | Masood <masood@masoodkamandy.com> |
|---|---|
| Date | 2018-07-30 08:35 -0700 |
| Message-ID | <c0db3d71-ac24-400d-a7d1-c7f78abfefc7@googlegroups.com> |
| In reply to | #4657 |
Thank you so much. A lot here I don't quite understand yet, but it's an awesome starting point for me to dig into. M
[toc] | [prev] | [next] | [standalone]
| From | David Schmidt <schmidtd@my-deja.com> |
|---|---|
| Date | 2018-07-30 13:21 -0400 |
| Message-ID | <pjnhee$pkc$1@dont-email.me> |
| In reply to | #4658 |
On 7/30/2018 11:35 AM, Masood wrote: > Thank you so much. > > A lot here I don't quite understand yet, but it's an awesome starting point for me to dig into. The thing to keep in mind with ca65 is that you can live your life without ever ORGing anything... you have a configuration or set of configurations that place the relocatable code where the config specifies. Personally, though, I often sprinkle in an ORG so that assembly listings are grounded in real locations instead of variable offsets.
[toc] | [prev] | [next] | [standalone]
| From | Masood <masood@masoodkamandy.com> |
|---|---|
| Date | 2018-08-01 16:38 -0700 |
| Message-ID | <67c316af-8770-4051-9629-dd2f9f0e267c@googlegroups.com> |
| In reply to | #4659 |
One more related question: For the sake of simplicity could I also just use labels in ca65 and relative addressing within the the "RODATA" segment, rather than creating my own new segments of memory at specific locations and modifying the config file for every project I do? This seems easier. Are there drawbacks to doing it that way? Thanks. M
[toc] | [prev] | [next] | [standalone]
| From | Michael J. Mahon <mjmahon@aol.com> |
|---|---|
| Date | 2018-08-01 18:47 -0500 |
| Message-ID | <3sednX2Z0e0Q2__GnZ2dnUU7-bPNnZ2d@giganews.com> |
| In reply to | #4660 |
Masood <masood@masoodkamandy.com> wrote: > One more related question: > > For the sake of simplicity could I also just use labels in ca65 and > relative addressing within the the "RODATA" segment, rather than creating > my own new segments of memory at specific locations and modifying the > config file for every project I do? > > This seems easier. Are there drawbacks to doing it that way? > > Thanks. > > M > If the tables are not page-aligned, you’ll take an extra cycle when indexing causes a page crossing. -- -michael - NadaNet 3.1 and AppleCrate II: http://michaeljmahon.com
[toc] | [prev] | [next] | [standalone]
| From | MG <*@guidero.us> |
|---|---|
| Date | 2018-08-02 15:06 -0700 |
| Message-ID | <a9bc5592-7f8d-4555-9cd6-1476c0149633@googlegroups.com> |
| In reply to | #4656 |
On Sunday, July 29, 2018 at 11:08:31 PM UTC-7, Masood wrote:
> I think problem is my lack of understanding of how a linker works, and how I would manipulate the config file.
>
> Does anyone have any resources, best practices, or sample code that might explain what a linker is and how a lookup table can be created in ca65?
I wanted to follow up on this part for you.
Traditional assemblers running on small 8-bit system would typically provide a few directives for code placement: the ORG directive, which as you know defines the "run" address of the assembled code, and the OBJ directive, DSK directive, or other directives to provide for the storage of the code.
At some point, especially in 16- and 32-bit systems, programs got so large that assembling them from single source files became problematic, as the source code is much larger than any given object code. Early directives for handling this supported "including" another file into the current assembly location.
Eventually, the need for reusable pre-assembled code modules arose, because re-assembling frequently-used code is time-consuming. Initially these were assembled for a specific location and loaded into that location at runtime, so the non-shared code only needed to know the fixed entry points.
However, this resulted in inflexibility and so the relocatable object module was developed. This is an intermediate assembled format that includes symbol information and code that is assembled effectively with a ORG address of 0. This is where the linker comes in.
In the case of the Apple II assemblers that use a linker (either separate or integrated), modules will export symbols via a directive, and modules wanting to use other modules will import the same symbols using another directive. The exported and imported symbols are written into the intermediate relocatable object module.
The linker's has two main jobs that it does to produce an executable output: (1) it places code in its final destination, and (2) it matches up all the imported symbols to exported symbols and computes the final addresses for all references to them.
In the case of ca65, the MPW and APW assemblers, and others, the assembler will convert any expressions in the assembly to a "calculator" format (often stack-based) in the object file so that things like LDA SOMELABEL+5 can be computed at linking time, rather than at assembly time.
ca65+ld65 (and some other assemblers+linker combinations) additionally support a mechanism for defining uninitialized vs initialized data modules, and defining code that loads in one place, but runs in another place. In ca65+ld65, this is where segments come in.
Segments are a tool that, along with a linker configuration file, allow finer control of the code placement and let you do things like define whether a segment is in ROM, RAM, data, etc., and optionally defines symbols that can be imported to locate where the linker placed stuff and where it should go. This gets important in a few scenarios: in the case of code that goes into ROM but must be copied to RAM and run, and where you have a "single file" program load that must move chunks of itself around in order to meet some constraint.
In that latter case, say you are working on an Apple II game that runs under ProDOS as a SYS file that uses the hi-res graphics page. Well, ProDOS loads your game at $2000, but you you can't just leave it there because that also happens to be where HGR page 1 lives. You could just put a jump in the beginning and maybe have a raw splash screen or something, followed by the code, but that's going to waste disk space. So you take advantage of the linker telling you where it put the code for load and where it put the code for execution, and write a small routine to move everything to where it's supposed to run.
Here's a linker config from one of my projects:
MEMORY {
LOAD1: start = $2000, size = $3F00;
RUN1: start = $8400, size = $3A00;
GLOBAL1: start = $BE00, size = $100;
}
SEGMENTS {
loader: load = LOAD1, align = $100;
global: load = LOAD1, run = GLOBAL1, define = yes, align = $100;
interp: load = LOAD1, run = RUN1, define = yes, align = $100;
code: load = LOAD1;
}
And here is the code that moves everything to where it ultimately belongs, which is in the loader segment:
LDR_MOVE_INTERP
lda #<__interp_LOAD__
ldy #>__interp_LOAD__
sta ZP_A1
sty ZP_A1+1
lda #<(__interp_LOAD__+__interp_SIZE__)
ldy #>(__interp_LOAD__+__interp_SIZE__)
sta ZP_A2
sty ZP_A2+1
lda #<__interp_RUN__
ldy #>__interp_RUN__
sta ZP_A4
sty ZP_A4+1
ldy #$00 ; required to move properly
jsr F8_MOVE ; firmware move routine
rts
; move globals, one page
LDR_MOVE_GLOBALS
ldx #$00
: lda __global_LOAD__,x
sta __global_RUN__,x
inx
bne :-
rts
As you can see, I don't need to worry much about where the linker places the various segments, or even the size of them (though I know the globals are $100 bytes). The loader code's run location is the same as its load location since it is not otherwise specified.
I hope that helps.
> For the sake of simplicity could I also just use labels in ca65 and relative addressing within the the "RODATA" segment, rather than creating my own new segments of memory at specific locations and modifying the config file for every project I do?
If you are using ca65/ld65 to their full abilities, each project will have its own configuration file. ld65 supplies some generic ones, but those are generally only useful in simple cases. A more complicated project isn't going to be able to make use of them.
> This seems easier. Are there drawbacks to doing it that way?
As Michael already mentioned, you really want to have your tables aligned for best performance. You can have them in one segment, and just fill the gaps with something else, and let the linker figure out the addresses for you. In that case you can change the tables to be something like what's below, and use the y2hgrL/H symbols directly, letting the linker sort them out.
Even better, you can separate them out into a separate file, add appropriate .export/.import y2hgrL and y2hgrH, and link it as an additional object, and the linker will sort it all out.
.segment "gBaseTable"
.align $100
y2hgrL: .byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $80,$80,$80,$80,$80,$80,$80,$80
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $28,$28,$28,$28,$28,$28,$28,$28
.byte $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.byte $50,$50,$50,$50,$50,$50,$50,$50
.byte $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
.res 64 ; skip to next page alignment
y2hgrH: .byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $00,$04,$08,$0C,$10,$14,$18,$1C
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $01,$05,$09,$0D,$11,$15,$19,$1D
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $02,$06,$0A,$0E,$12,$16,$1A,$1E
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
.byte $03,$07,$0B,$0F,$13,$17,$1B,$1F
MG
[toc] | [prev] | [standalone]
Back to top | Article view | comp.sys.apple2.programmer
csiph-web