Hello, Guest the thread was called552 times and contains 17 replays

last post from Snoopy at the

Problem with LDA_FAR

  • Before I go to the basement and start crying ... :cry:

    First I want to describe, what I want to do:

    - read the value of address $1000 in bank 4 ($041000) into register A

    How I want to do it:

    - use the kernel routine $FF74 (LDA_FAR):

    - with this code:

    1. lda #$00 ; 00 -> $FB
    2. sta $fb
    3. lda #$10 ; 10 -> $FC, so $FB/$FC = $1000
    4. sta $fc
    5. ldx #$fb ; X = $FB
    6. ldy #$00 ; Y = 0
    7. ldz #$04 ; Z = 4 for using bank 4
    8. jsr $FF74 ; call lda_far

    But I never get the value of address $041000 into register A.

    In $FB/$FC the $1000 is stored correct.

    Anyone any idea what's wrong? :/

  • Anyone any idea what's wrong?

    Use TedMON and take a look at what the LDA_FAR kernal routine actually does. The description ("DMA list update") sounds like a valid workaround to the "the memory configuration can only ever be written" problem - but does the DMA hardware even exist in your setup?

    I know this does not solve the actual problem, but still: I think it does not make much sense to use the *_FAR routines in your own programs. Just like on the C128, they are only really needed as wrappers so the machine's BASIC can supply the user with working POKE/PEEK/SYS routines. For everything else, it is much simpler to just write your own routines.

  • But the lda_far kernel routine is one if the most used routines of the BASIC 10. Variables are stored in bank 1 and the code in bank 0. Every time a code or variable is used, lda_far or sta_far were called by the BASIC interpreter. I really see no need to program a routine of my own if such a code exists.

    The thing is, that it seems I have errors in calling it correctly. :S

  • Have you perhaps used some stack operations going somewhat deeper into the stack some time before (e.g. multiple nested subroutine calls for a recursive algorithm, or anything else much more than usual), or saved or written anything in the stack page by hand? If so, then the DMA tables might get overwritten by accident (thus the system DMA won't work any more).

    That's because when the operating system initalizes, it puts the DMA tables right in the middle of the stack page, which is unfortunately a little bit dangerous place for them...

    I made some disassembly of the Kernal code a few years ago, since I also used these calls in a test program of mine, and wanted to see what they do, then I wrote a documentation about it here (see pages 44-48, as even some program lists are there):


  • Sorry, I'm really a fan of the C65, but this is where it gets ridiculous for me:

    I have to set the DMA registers with the values for the DMA list, but I have no way to query what's in here because the registers are "write only" registers?

    Who thinks up something so stupid? :wand

  • For the sake of completeness, here is the text from the MEGA65 manual (currently on page 681):

    Quote from mega65-book.pdf (page 681)

    F018A/B DMA JOBS

    To execute a DMA job using the F018 series of DMA controllers, you must construct the list of DMA jobs in memory, and then write the address of this list into the DMA address registers. The DMA job will execute when you write to the ADDRLSBTRIG register ($D700). For this reason you must write the MSB and bank number of the DMA list inti $D701 and $D702 first, and the LSB only after having set these other two registers. If you wish to execute multiple DMA jobs using the same list structure in memory, you can simply write to ADDRLSBTRIG again after updating the list contents – provided that no other programme has modified the contents of $D701 or $D702. Note that BASIC 65 uses the DMA controller to scroll the screen, so it is usually safest to always write to all three registers.

  • For my understanding, the DMA list parameters are being set by the LDA_FAR routine:

    1. FF74 4C F2B3 8599 jmp lda_far ;LDA (X),Y from bank Z

    That is what I have got give with on entry: "lda_far ;enter with .a=????, .x=vecptr, .y=index, .z=bank"

    X,Y and Z as I do in my first post. But it is not working this way. ;(

  • I don't get it ...

    Here is a screenshot to show the problem:

    In $41000 (bank 4) is "AA".

    In $FB/$FC the values "00" and "10" for $1000 will be stored.

    X is loaded with #$FB, Y with #$00 and Z with #$04 (for bank 4).

    Then the LDA_FAR routine is called. All of that with interrupts disabled.

    After that in A should stand "AA" (for the value of $41000). But it's "60". :|

  • I know, that it is off topic but thanks for this document. I like platform independent coding. ;-)

    You're welcome! I have not seen your page yet, till now, but it seems there are a lot of similarities with my own project. (Mein Deutsch ist leider nicht so gut, aber ich kann ein bisschen langsammer das lesen.) :thumbup:

  • After that in A should stand "AA" (for the value of $41000). But it's "60".

    I'm not convinced, because the program counter in that line is off as well. Are you sure the monitor is working correctly? Do not rely on the firmware while investigating the firmware. Question everything. :D

    Maybe use the old debugging method of sprinkling your code with "inc $d020" instructions, that should help to clear things up quickly.

    Once the current problem is solved:

    ...having now read about how the DMA stuff is supposed to work, I'm back to "don't use LDA_FAR". Just setup your own (static!) dma list in memory and write its address to the dma registers. The resulting code would be both shorter and faster.

  • You should check these following:

    1.) VIC-III or VIC-IV mode should be enabled ($d02f).

    2.) You should have the standard zero page (not a relocated one).

    3.) You have to (!) have the standard stack page, too (not relocated), since the DMA tables are there (and also check for them not being overwritten accidentally).

    4.) The Kernal ROM code must be banked in (of course). Make sure if it is the C65 Kernal (and not the C64 one by chance). Also make sure if the I/O area is banked in. The best to try to start it with a BANK 128 setup at the first time.

    Since the DMA byte is stored at $015c according to the ROM code disassembly above, check this location for being the same what you can see in the A register (whether or not the function has been executed).

  • Since the DMA byte is stored at $015c according to the ROM code disassembly above, check this location for being the same what you can see in the A register (whether or not the function has been executed).

    Thanks! :thumbup:

    Okay, the "AA" is in $015c. So at least something works. :)

    Edit: But only once. A second call or more the value of $015c seems to be random ... but at least I have something to search on ...

  • I'm currently at a point where I'm going to let the whole thing rest for a while. ;(

    I don't mind a challenge and I'm quite happy to get stuck into software problems.

    But there is a line between "challenge" and "obstacles and problems as far as the eye can see" and that in my spare time. :cursing:

    Beyond a certain point, it's simply no longer fun for me. For me, it no longer has anything to do with "tinkering" when even the simplest things are close to being "impossible to implement" and I have to spent days and days for it. And the documentation available so far for such "basics" can hardly be used. This is all still described "much too abstractly".

    I want to program an 8-bit computer and not write a doctoral thesis! :whistling:

    I really praise the C64! I know what I got out of it. :D

    Sorry, but the current frustration just had to come out! :(