03/15/07: If it’s the wrong section, please say so … by RetroRick, | Category: General | 42 comments - (Comments are closed)

If it’s the wrong section, please say so …

Any suggestions anyone? There’s a USR subroutine that scrolls the wrong part of the screen when the Disk System is enabled. Here’s some of the code:


CODE
4 DEFUSR0=474:DEFUSR1=490:FORX=474TO484:READY:POKEX,Y:NEXT:FORT=490TO542:READZ:POKET,Z:NEXT
5 DATA 173,159,160,10,79,246,01,93,126,180,244,16,142,25,223,16,191,63,226,142,25,192,198,1,166,132,183,63,225,58,166,132,167,31,188,63,226,38,246,182,63,225,167,132,30,18,198,32,58,198,1,30,18,16,191,63,226,58,140,27,192,38,217,57

The rest of the code is just ECB using the USR routine or doing typical, vanilla ECB commands (LINE and GET among other things).

42 comments to If it’s the wrong section, please say so …

  • tlindner

    That copies a small program into the casette I/O buffer. And points USR0 to it:


    CODE

    Â jsr [$A00A]
    Â clra
    Â ldb $015d
    Â jmp $b4f4

    This means USR0 will read both axis on both joysticks, then return the Right Horizontal joystick value.

    Here is my disasembly of what is put under USR1:

    CODE

       ldy #$19df
       sty $3fe2
       ldx #$19c0
       ldb #$01
    lp1 lda ,x
       sta $3fe1
    lp2 abx
       lda ,x
       sta -$1,x
       cmpx $3fe2
       bne lp2
       lda $3fe1
       sta ,x
       exg x,y
       ldb #$20
       abx
       ldb #$01
       exg x,y
       sty $3fe2
       abx
       cmpx #$1bc0
       bne lp1
       rts

    I’m still studying it.

  • mannequin

    Side note: Looks to me to be in the right place. Even though it’s in BASIC, it has a whole lotta ASM in there. wink.gif

    -M.

  • Robert Gault

    Here’s an educated guess at the problem.

    The code seems to have hard coded the memory that gets scrolled. That will work if there are no changes to the system but that is not the case when going from a tape to disk system; moving the graphics screen in memory.

    With everything else being unchanged, the code probably can be “corrected” by adding an offset to the memory addresses on the graphics screen. The shift from ECB to Disk ECB is $600 to $E00 or $800 bytes. So, it looks like you could add $800 to $19DF, $19C0, and $1BC0 and the code should work.
    $19DF+$800=$21DF
    $19C0+$800=$21C0
    $1BC0+$800=$23C0

    It may be necessary to shift the locations of any ml code if the code falls into the graphics screen on a Disk system. However, as the program did not crash but merely moved the wrong screen data, I’d guess nothing else needs to be altered.

  • RetroRick


    QUOTE
    The code seems to have hard coded the memory that gets scrolled. That will work if there are no changes to the system but that is not the case when going from a tape to disk system; moving the graphics screen in memory.

    With everything else being unchanged, the code probably can be “corrected” by adding an offset to the memory addresses on the graphics screen. The shift from ECB to Disk ECB is $600 to $E00 or $800 bytes. So, it looks like you could add $800 to $19DF,  $19C0, and $1BC0 and the code should work.

    That was my thought, too. However, it isn’t obvious to me what numbers in the DATA statements I need to change, and how. Is there a program you could point me to that converts ASM into binary form? Thanks. :-)

    Tim -

    QUOTE
    This means USR0 will read both axis on both joysticks, then return the Right Horizontal joystick value.
    That’s *really* weird, since the game only uses the vertical coordinates of the Left Joystick for control, and there are no JOYSTK(3) statements. blink.gif
  • Robert Gault

    One of my pet peeves is assembly code that uses decimal addressing, the same with POKEs. If you are going to program in assembly, learn to use and think in the address size of the CPU in use. That means on a Coco addresses are $xxxx.

    That being said, either use a calculator with decimal to hexadecimal conversion or use the Coco to make the conversion of the POKE data. Then you will see which data bytes to change because the addresses given in my previous message will match the data.

  • RetroRick


    QUOTE (Robert Gault @ Mar 16 2007, 08:39 PM)
    That being said, either use a calculator with decimal to hexadecimal conversion or use the Coco to make the conversion of the POKE data. Then you will see which data bytes to change because the addresses given in my previous message will match the data.

    You mean there’s one byte as $19 and the next byte is $DF? Sorry; I didn’t know it worked that way. blink.gif
  • RetroRick

    Thank you for all your help so far. The line now reads:


    CODE
    5 DATA 173,159,160,10,79,246,01,93,126,180,244,16,142,33,223,16,191,63,226,142,33,192,198,1,166,132,183,63,225,58,166,132,167,31,188,63,226,38,246,182,63,225,167,132,30,18,198,32,58,198,1,30,18,16,191,63,226,58,140,35,192,38,217,57

    However, when running the program, Line 88 reads like this before you RUN the program:

    CODE
    88 P=USR1(P):IFDX+6>EY-2ANDDX+6DY-10  THEN SL=SL-1:SCREEN0,1:PRINT:SCREEN1,1:PLAYVL$:PUT(EX,EY)-(EX+21,EY+11),E1,PSET:EX=240:GOSUB65:IF SL=0THEN 54 ELSEONSL GOTO67,66

    … to this when the USR commands are executed:

    CODE
    88 P=USR

    It doesn’t do this if I precede the RUNing of the program with a PCLEAR 5 command. Have I done something wrong? sad.gif

  • Robert Gault

    That would seem to confirm the program hard codes the screen location rather than using Basic to access it. After you patched the code to affect memory at a higher location than on a tape system, you trashed the Basic program which did not move.
    The PCLEAR statement reserved more graphics memory and moved the Basic program into a safe location.

    You have not said whether the game now behave correctly when you do use PCLEAR. It is likely that a simple patch will not be sufficient or that my idea was completely wrong.

  • RetroRick

    Sorry about that, Robert. sad.gif

    Once I got the program running with the PCLEAR 5, the scrolling was fixed, yes; thank you very much. smile.gif

    But I found out that PCLEAR 5 just trashes the routine used when you get to enter your name in the high score charts. The only way to save all ECB content from corruption is by truncating the code (and removing semicolons in several DRAW commands, among other things) and giving it a PCLEAR 8. Doing a PCLEAR 7 keeps the program code itself from being corrupted, but then the contents of a string array are hacked off. Very strange. blink.gif

  • jdiffend

    If you don’t want the routine to get trashed poke it into a string variable.
    Use varptr() to get the address of the string.

    Once your routine is in the string you can delete the loop and data. Just save it with the USR routine in the string. Just don’t try to edit the line it’s on or you’ll trash it.
    Or you could leave the routine that loads it in the program but just not call it. That way if it does get trashed just re-enable it.
    Oh yeah, and make sure the string is long enough to hold the routine before you poke in the machine code.

    It would look something like this before you run it but I’m not certain since I haven’t used it since 1983. After you run it the string will appear to contain garbage or tokens when you list the program.

    10 A$=”01234567890123456789012345678901234567890123456789012345678901234″
    20 ADR=VARPTR(A$) ‘GET ADDRESS OF A$
    30 GOSUB 10000 ‘LOAD USR ROUTINE INTO A$
    40 ‘SET USR CALL ADDRESS HERE

    10000 ‘LOAD USR ROUTINE INTO A$
    10020 FOR I=1 TO 64 : READ J : POKE ADR+I,J : NEXT I
    10030 RETURN
    10040 DATA…


    This is from the TRS-80 Level II docs. The coco VARPTR() will probably be similar.
    VARPTR ( V ) returns I

    Returns the memory address of the variable V. For a numeric variable, this is the actual address of the low-order byte of the number (see above for details on how numbers are stored in memory). For a string variable, the address returned by VARPTR is the address of the three-byte record containing the string’s length and a pointer to its data (see above for details on how strings are stored in memory). Note that position (I – 3) holds the variable’s type (2 for integer, 3 for string, 4 for single, and 8 for double), and positions (I – 2) and (I – 1) hold the first two characters in the variable’s name.

    So we should skip the string length to point to the pointer to the string.
    That’s VARPTR()+1 and VARPTR()+2
    So….

    20 ADR=VARPTR(A$) ‘GET ADDRESS OF A$

    should read more like…

    20 T=VARPTR(A$)+1 : ADR = PEEK(T) + PEEK(T+1)*256 + 9 ‘GET ADDRESS OF A$

    I don’t know why 9 but this is what works to load the string. Make sure you save the program before you run it because it won’t be editable after the code is loaded in the string. At least that’s what happened for me.

    My string was too short and it overwrote some of the code. The attached disk image has the correct code.

  • RetroRick

    Jdiffend, thanks for trying to help me out here, but there’s two problems with your approach.

    1 – The USR routine itself is not getting trashed. A line of the ECB code or the contents of a string array are getting hacked off.
    2 – Your method expands the size of the program, and the scrolling routine alters the code of the program when it’s too big.

  • jdiffend


    QUOTE (RetroRick @ Mar 19 2007, 08:30 PM)
    Jdiffend, thanks for trying to help me out here, but there’s two problems with your approach.

    1 – The USR routine itself is not getting trashed. A line of the ECB code or the contents of a string array are getting hacked off.
    2 – Your method expands the size of the program, and the scrolling routine alters the code of the program when it’s too big.


    Actually, if you have the program exit after it loads the USR functions in the string you can delete the loops and data statements used to load it and save the program with the USR routine in the string. That should make it smaller than it already is. Just remember to keep a copy of the original in case you mess up and edit the string.

    On top of that, you might be able to use the address of the string to calculate the base address to poke into the USR function for the address of the screen.
    Without having more of the program to look at I can’t tell you what the offsets would be but if you know where in the string to poke it shouldn’t be tough.

    Just remember, anything that might move the string will require you to change the address for the USR routines.
    BTW, the string could be loaded with 1 loop but I duplicated the way it worked in your code in case the bytes between the 2 USR functions was required. Even so, it would be shorter to add 0′s to the data statements to provide the gap and just use one loop.

  • jdiffend


    QUOTE
    On top of that, you might be able to use the address of the string to calculate the base address to poke into the USR function for the address of the screen.
    Without having more of the program to look at I can’t tell you what the offsets would be but if you know where in the string to poke it shouldn’t be tough.

    Just to clarify this a little…
    All this would require is something like:
    50 IF ADR <> cassetteaddressofa THEN POKE ADR+offset,data : POKE… POKE…

    Since the USR function already contains the cassette address you don’t need to modify the address if you find A$ at the expected address for a cassette system.
    You can just hard code the pokes for the proper address used by DECB.

    QUOTE
    Just remember, anything that might move the string will require you to change the address for the USR routines.

    By that, I mean any string function that modifies A$ will move it and you’ll need to redo the VARPTR line to calculate the address.
    Normally, this will never happen but it is possibly to change a user function with string functions.
    You can put a user function in a string without some needed data and then just tack on the data with string functions. Or part of the USR function could change with different levels of a game and you could just build a new string based on that without using slower POKEs.
  • RetroRick


    QUOTE (jdiffend @ Mar 20 2007, 03:05 AM)
    Without having more of the program to look at I can’t tell you what the offsets would be but if you know where in the string to poke it shouldn’t be tough.

    I’ll try posting the program here.

    Hm, it’s lined up a little hard to read when I loaded it up. Should I try something else? unsure.gif

  • jdiffend


    QUOTE (RetroRick @ Mar 20 2007, 07:16 PM)
    I’ll try posting the program here.

    Hm, it’s lined up a little hard to read when I loaded it up.  Should I try something else?  unsure.gif


    Never mind… nothing seems to be missing. It just didn’t save correctly for me the first time.
    I’ll see what I can do with it.
  • Robert Gault

    The program as posted has errors and/or missing lines. Line 63 calls a line 84 which is not present. Also there is a test for A$ in line 63 which does not include the possibility of an empty string. When I ran the program, A$ was empty and gave an FC error in line 63 for KN=ASC(A$)-65.

    ASC(A$) will give an FC error when LEN(A$)=0.

  • jdiffend

    My use of VARPTR was off. Dumb luck made it work out.
    I’ll post a fix a little later.

    Wrong:
    T=VARPTR(US$)+1:ADR=PEEK(T)+PEEK(T+1)*256+9:DEFUSR0=ADR:DEFUSR1=ADR+16

    Correct:
    T=VARPTR(US$)+2:ADR=PEEK(T)*256+PEEK(T+1):DEFUSR0=ADR:DEFUSR1=ADR+16

    My original guess that the address was in big endian format was correct.
    That explains why I had to add 9 in my sample code… which just didn’t make sense to me but it worked.

  • jdiffend


    QUOTE (Robert Gault @ Mar 20 2007, 09:50 PM)
    The program as posted has errors and/or missing lines. Line 63 calls a line 84 which is not present. Also there is a test for A$ in line 63 which does not include the possibility of an empty string. When I ran the program, A$ was empty and gave an FC error in line 63 for KN=ASC(A$)-65.

    ASC(A$) will give an FC error when LEN(A$)=0.


    That’s what I thought at first… then I saved it directly without looking at the file and everything was there.
  • jdiffend


    QUOTE (Robert Gault @ Mar 16 2007, 09:24 AM)
    Here’s an educated guess at the problem.

    The code seems to have hard coded the memory that gets scrolled. That will work if there are no changes to the system but that is not the case when going from a tape to disk system; moving the graphics screen in memory.

    With everything else being unchanged, the code probably can be “corrected” by adding an offset to the memory addresses on the graphics screen. The shift from ECB to Disk ECB is $600 to $E00 or $800 bytes. So, it looks like you could add $800 to $19DF,  $19C0, and $1BC0 and the code should work.
    $19DF+$800=$21DF
    $19C0+$800=$21C0
    $1BC0+$800=$23C0

    It may be necessary to shift the locations of any ml code if the code falls into the graphics screen on a Disk system. However, as the program did not crash but merely moved the wrong screen data, I’d guess nothing else needs to be altered.


    Robert, I just looked at the disassembly. That fixes the screen address but still leaves other things unpatched.

    It also uses $3f31 and $3fe2.

  • jdiffend

    Ok, I seem to have fixed the machine code and have it located in the string but now I get a syntax error on one of the lines.
    I’m guessing the cutting and pasting the code in the emulator didn’t work 100% of the time.

    Once I get it working I’ll post a disk image.

    BTW, I just had to move the temp locations it was using into the extra space I reserved in the string. POKE POKE POKE POKE….

  • jdiffend

    After searching through the code, I can’t find USR0() being called anywhere.
    If that’s the case, it could be dropped from the data along with the loop that POKEs it into memory.

    I’m still seeing a couple bytes of code getting trashed so I’ll need to find where the problem is.

    It’s called with USR() instead of USR0() in line 39.


    The BASIC code is trashing memory with POKEs from the look of things. I’ll look at fixing that tomorrow. Line 60 needs modified to use a variable for the screen address rather than a hard coded address. POKE is used a couple other places but I’m not sure if that’s a problem.

  • Robert Gault

    You will find things much easier if you use an editor/assembler to create ml code to be LOADMed into memory instead of the POKE DATA routine.

    As it turns out, the $3FE1 & $3FE2 would have been after the Basic program on a tape system. Now that you are using a disk system, you need to offset these addresses as well. However when that is done with a PCLEAR8, you defeat the purpose of the shift to $3FE1 and will trash the Basic program.

    Patch all of the addresses in the ml routine including $3FE1 and $3FE2 and use PCLEAR4.

    By the way, the ml routine is not optimal code. The section
    EXG X,Y
    LDB #32
    ABX
    LDB #1
    EXG X,Y
    can easily be replaced with
    LEAY 32,Y

    For that matter the code could be adjusted to use LDA ,X+ to get rid of the LDB #1 and ABX but that might not be worth the effort.

  • jdiffend


    QUOTE
    You will find things much easier if you use an editor/assembler to create ml code to be LOADMed into memory instead of the POKE DATA routine.

    But that won’t run on both cassette and disk.

    QUOTE
    As it turns out, the $3FE1 & $3FE2 would have been after the Basic program on a tape system. Now that you are using a disk system, you need to offset these addresses as well. However when that is done with a PCLEAR8, you defeat the purpose of the shift to $3FE1 and will trash the Basic program.

    Patch all of the addresses in the ml routine including $3FE1 and $3FE2 and use PCLEAR4.


    I already have them patched, I just haven’t used PCLEAR8. If all that is needed is PCLEAR 4, then why PCLEAR 8? Wouldn’t PCLEAR5 suffice? But then I haven’t used ECB in a long time.

    QUOTE
    By the way, the ml routine is not optimal code. The section
    EXG X,Y
    LDB #32
    ABX
    LDB #1
    EXG X,Y
    can easily be replaced with
      LEAY 32,Y

    For that matter the code could be adjusted to use LDA ,X+ to get rid of the LDB #1 and ABX but that might not be worth the effort.


    For that matter, since I’m placing the code in a string the $3fe1 and $3fe2 could be moved to just after the program and the entire thing could be scrunched together to simplify the POKE routines.
  • Robert Gault

    No, aside from the lea (typo? should be leay) you will still have problems because you have not shifted screens 1, 2, or 3. Did you modify the USR# defines to the new location? If not, that would give you another error.
    Are ldy screen1, ldx screen2, cmpx screen3 more typos? They should be ldy #screen1, ldx #screen2, and cmpx #screen3

    If you are using an assembler to determine the code, you could define a new variable.
    shift equ $E00-$600

    Then you could add shift to any address needing to be changed. Only one line would need to be changed to alter the shift.

    ldy #screen1+shift instead of ldy #screen1

  • jdiffend


    QUOTE
    No, aside from the lea  (typo? should be leay) you will still have problems because you have not shifted screens 1, 2, or 3. Did you modify the USR# defines to the new location? If not, that would give you another error.
    Are ldy screen1, ldx screen2, cmpx screen3 more typos? They should be  ldy #screen1,  ldx #screen2, and cmpx #screen3

    If you are using an assembler to determine the code, you could define a new variable.
    shift equ $E00-$600

    Then you could add shift to any address needing to be changed. Only one line would need to be changed to alter the shift.

    ldy #screen1+shift        instead of      ldy #screen1


    Already caught the LEAY typo when I went to assemble it.
    You posted right when I was deleting the post to include a fixed version.

    I’m poking in the addresses if it’s not a cassette system so the screen offset is fixed by the BASIC code.
    This lets one BASIC program run on either setup.
    Once the program has been run once you can delete the loop and data that inserts the assembly in the string and save it if you don’t want the load/patch to run every time.

    The PC relative addressing added something like 10 bytes so I removed it and reverted back to modifying at multiple places rather than trying to isolate it to one area. I’m still toying with adding it back in at the start of the loop but not using it within the loop. That way it only adds a few clocks at the start but reduces the number of POKEs. Your optimization would still make it faster in the end.

    CODE

                 {$0000}  offset            equ  #0
                 {$19DF}  screen1           equ  #$19df+offset
                 {$19C0}  screen2           equ  #$19c0+offset
                 {$1BC0}  screen3           equ  #$1bc0+offset
                                               
                          start             org  $37bc+offset;string address for cassette
    37BC AD   9F A00A     USR0              jsr  [$A00A];get input from joystick
    37C0 4F                                 clra  
    37C1 F6   015D                          ldb  $015d;convert to a float and return
    37C4 7E   B4F4                          jmp  $b4f4;rts in function will return to BASIC
                                               
                          label1              
    37C7 108E 19DF        USR1              ldy  #screen1
    37CB 10BF 37F7                          sty  temp2
    37CF 8E   19C0        label2            ldx  #screen2
    37D2 C6   01                            ldb  #$01
    37D4 A6   84          lp1               lda  ,x
    37D6 B7   37F6                          sta  temp1
    37D9 3A               lp2               abx  
    37DA A6   84                            lda  ,x
    37DC A7   1F                            sta  -$1,x
    37DE BC   37F7                          cmpx  temp2
    37E1 26   F6                            bne  lp2
    37E3 B6   37F6                          lda  temp1
    37E6 A7   84                            sta  ,x
    37E8 31   A8 20                         leay  #32,y
                       ; the previous line replaces this
                       ; exg x,y
                       ; ldb #$20
                       ; abx
                       ; ldb #$01
                       ; exg x,y
    37EB 10BF 37F7                          sty  temp2
    37EF 3A                                 abx  
    37F0 8C   1BC0        label3            cmpx  #screen3
    37F3 26   DF                            bne  lp1
    37F5 39                                 rts  
                                               
                       ;screen1 fdb #$19df
                       ;screen2 fdb #$19c0
                       ;screen3 fdb #$1bc0
                                               
    37F6 00               temp1             fcb  0
    37F7      0000        temp2             fdb  0
                                               
                 {$0000}                    end  
  • jdiffend


    CODE

                 {$0800}  offset            equ  #$E00-#$600
                 {$21DF}  screen1           equ  #$19df+offset
                 {$21C0}  screen2           equ  #$19c0+offset
                 {$23C0}  screen3           equ  #$1bc0+offset
                                               
                          start             org  $37bc+offset;string address for cassette
    3FBC AD   9F A00A     USR0              jsr  [$A00A];get input from joystick
    3FC0 4F                                 clra  
    3FC1 F6   015D                          ldb  $015d;convert to a float and return
    3FC4 7E   B4F4                          jmp  $b4f4;rts in function will return to BASIC
                                               
                          label1              
    3FC7 108E 21DF        USR1              ldy  #screen1
    3FCB 10BF 3FF7                          sty  temp2
    3FCF 8E   21C0        label2            ldx  #screen2
    3FD2 C6   01                            ldb  #$01
    3FD4 A6   84          lp1               lda  ,x
    3FD6 B7   3FF6                          sta  temp1
    3FD9 3A               lp2               abx  
    3FDA A6   84                            lda  ,x
    3FDC A7   1F                            sta  -$1,x
    3FDE BC   3FF7                          cmpx  temp2
    3FE1 26   F6                            bne  lp2
    3FE3 B6   3FF6                          lda  temp1
    3FE6 A7   84                            sta  ,x
    3FE8 31   A8 20                         leay  #32,y
                        ; the previous line replaces this
                        ; exg x,y
                        ; ldb #$20
                        ; abx
                        ; ldb #$01
                        ; exg x,y
    3FEB 10BF 3FF7                          sty  temp2
    3FEF 3A                                 abx  
    3FF0 8C   23C0        label3            cmpx  #screen3
    3FF3 26   DF                            bne  lp1
    3FF5 39                                 rts  
                                               
                        ;screen1 fdb #$19df+offset
                        ;screen2 fdb #$19c0+offset
                        ;screen3 fdb #$1bc0+offset
                                               
    3FF6 00               temp1             fcb  0
    3FF7      0000        temp2             fdb  0
                                               
                 {$0000}                    end  
  • RetroRick


    QUOTE (Robert Gault @ Mar 21 2007, 02:56 AM)
    You will find things much easier if you use an editor/assembler to create ml code to be LOADMed into memory instead of the POKE DATA routine.

    I’d love to use one, but all I have at the time is a corrupted version of EDTASM which won’t start the “E” mode (It gives me a buffer error with this command).

    I’ll see about locating every occurrence of USR0 and USR1 in the code and list them here. Hope to post it here later tonight.

    Thanks for all your help here, guys. biggrin.gif

  • jdiffend

    It seems to be crashing in line 36 in the original code.
    It works up till the USR call. Something still isn’t right.

    I’ll attach a disk image with what I’ve changed. It’s line 37 in the new version.
    Since I don’t know what screen address the coco uses I have no idea what’s up.
    It looks like it scrolls once.

    Rick, download the Rainbow IDE. It has cross assemblers with it.

    Check out the file DEFEND3.BAS, I had it pause right before each USR1 call. The first one seems to at least partially work but it locks up after that.
    That should have the new data in it. The load routine and patch routine start at line 79 or something like that. That part does seem to work fine. Something about the USR1 routine must be wrong. Is everyone certain that’s the proper screen address?

  • RetroRick

    The first occurrence of the USR calls (USR1) are in Line 36 of the program, used at the tail end of the program line. It’s placed inside a FOR/NEXT loop.

    The rest of the USR calls are in Lines 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, and 88 of the code. The first occurrence in those lines are in Command #1 or Command #2.

    Thanks for the pointer to Rainbow IDE, BTW. smile.gif I’d forgotten for some reason. sad.gif

  • RetroRick


    QUOTE (jdiffend @ Mar 21 2007, 07:35 PM)
    It seems to be crashing in line 36 in the original code.
    It works up till the USR call. Something still isn’t right.

    I’ll attach a disk image with what I’ve changed. It’s line 37 in the new version.
    Since I don’t know what screen address the coco uses I have no idea what’s up.


    Thanks for the attachment. I can see part of what’s going on, anyway.

    First off, the programs DEFEND3 and DEFEND4 are considerably bigger than DEFEND2. As I said before, if the program’s too big, the USR1 routine will be hacking off either the lines of the program itself, or the contents of its string arrays. I haven’t run the programs myself yet, but I’m pretty sure that’s at least part of the problem here.

  • jdiffend

    Well, what’s most important is WHY it’s overwriting the code. The length of the code shouldn’t be an issue. The USR1 routine should only be messing with screen memory. Not only that, it appears to be overwriting the first few lines of the BASIC code. I saw garbage appearing in line 3. If it’s trashing that, making the program shorter won’t help.

    I think the reason it’s overwriting code is because an address in the USR1 function is wrong. I may know quite a bit about assembly and have used stuff like VARPTR before but I really don’t know advanced in’s and out’s of the Coco.

    The new version of the USR1 routine is actually smaller than the original.
    If you want to make the DATA statements take up less room you can convert the rest hex numbers (&H) to decimal. I only converted enough for the USR routines to fit in one line. The 2nd group of data I added is the patches for DECB. The first number is the number of patches and the rest are pairs of offsets in the string and the patch for that offset. This approach *should* let the program run under DECB or ECB.

    Once you have run the program once you can delete the lines associated with loading the USR routines in the string and save the program. The USR routines will still be in the string and it will be saved that way. However, the program will only work on DECB if it was originally run on DECB or ECB if it was run under ECB.

  • jdiffend

    BTW, I’m not as worried about the USR calls as I am about the POKEs.
    I fixed one loop that poked zeros to the screen to use the new screen address but I’m still not sure that’s correct. The others… I have no idea what they might overwrite. If one were to overwrite a pointer used by the OS… all sorts of bad things could happen.

  • RetroRick


    QUOTE (jdiffend @ Mar 21 2007, 10:37 PM)
    Once you have run the program once you can delete the lines associated with loading the USR routines in the string and save the program.  The USR routines will still be in the string and it will be saved that way.  However, the program will only work on DECB if it was originally run on DECB or ECB if it was run under ECB.

    But this would cause problems if you restarted the machine and re-ran the saved program, right? Wouldn’t it make more sense to tell the program to delete the lines with the USR data in it after it’s loaded up?

    And actually, since each value POKEd in would range from Zero to 255, couldn’t you take all the data for the USR routines, and put everything into a string, with each byte representing two bytes in the string?

    What I mean is – Suppose you had the values 0, 255, and 9 to POKE in. These are &H00, &HFF, and &H09 in Hexadecimal form. In the string, they’d be represented as:

    “00FF09″

    You can have ECB change each value to Hex form, store it into a string, then write it to an ASCII file on disk. Is it harder to read this way? Yes. But does save room, and makes it easier when comparing it with the ASM version of the routine. But that’s only if the routine extracting the data to POKE in doesn’t take up more room than the original version.

  • RetroRick


    QUOTE (jdiffend @ Mar 22 2007, 12:58 AM)
    BTW, I’m not as worried about the USR calls as I am about the POKEs.
    I fixed one loop that poked zeros to the screen to use the new screen address but I’m still not sure that’s correct. The others… I have no idea what they might overwrite. If one were to overwrite a pointer used by the OS… all sorts of bad things could happen.

    The addresses for the DECB OS go from &H0600 (1536) to &H0DFF (3583). That’s 2Ks worth.
  • jdiffend


    QUOTE
    But this would cause problems if you restarted the machine and re-ran the saved program, right?  Wouldn’t it make more sense to tell the program to delete the lines with the USR data in it after it’s loaded up?

    Once the USR routine is loaded in the string, if you save the program, the USR routine will still be in the string the next time you load it. As long as the program loads at the same address it will always work. I could modify the patch routine to calculate the patches rather than have them stored with the offsets in the data and as long as that’s left in place it would always run even on cassette. However, I’d have to know how to calculate the location of the graphics screen buffer.
    It involves something like this (not completely BASIC here):

    current_address = PEEK(USR_offset)*256 + PEEK(USR_offset +1)
    new_address = current_address + new_destination_offset
    byte_one = INT(new_address/256)
    byte_two = new_address – (byte_one * 256)
    POKE(USR_offset, byte_one) : POKE(USR_offset+1, byte_two)

    It’s shorter with real variables but that’s the idea.

    I don’t think BASIC will be able to continue execution after deleting a line but I haven’t done anything like that since around 1982.

    QUOTE
    And actually, since each value POKEd in would range from Zero to 255, couldn’t you take all the data for the USR routines, and put everything into a string, with each byte representing two bytes in the string?

    Actually, yes you can do that. With a large amount of data it is much more efficient space wise. However, since the routine to load the data is longer it’s a trade-off. It would probably cut the data almost in half compared to comma separated decimal numbers so it might be the way to go. But if you delete the data once it’s loaded you won’t gain anything. It *is* easier to take from the assembler output though.

    QUOTE
    You can have ECB change each value to Hex form, store it into a string, then write it to an ASCII file on disk.  Is it harder to read this way?  Yes.  But does save room, and makes it easier when comparing it with the ASM version of the routine.  But that’s only if the routine extracting the data to POKE in doesn’t take up more room than the original version.

    Or if you knew the number of bytes in the data set (and we do) you could create a string twice the length and directly POKE the ASCII data into in after getting it’s location with VARPTR. Then you could edit the line and change it from a string assignment (D$=”….”) to a DATA statement.

    However, you are still blaming program length and that doesn’t solve the underlying problem. Something is overwriting memory it shouldn’t.

  • RetroRick

    I think I’ve figured out what’s wrong in the DEFEND4 code; there’s two lines that seem to reference the incorrect variables.


    CODE
    81 IF ADR<>16316 THEN READX:FOR I=1 TO X:READ Y,Z:NEXT:RETURN

    This reads two numbers from the DATA statements into variables X and Y for each count in a FOR/NEXT loop using the I variable … and no POKE commands appear at all in this loop.

    CODE
    82 READX:FORI=1 TO X:READ Y,Z:POKE ADR+Y,Z:NEXT:RETURN

    This line reads two numbers into variables X and Y once again for each count of I’s FOR/NEXT loop, then POKEs in ADR+Y,Z. It’s I that’s being incremented, not Y, whose value equals whatever was stored into it when reading a value from the DATA statements.

    I’d post a correction, but I’m not really sure what exactly you were trying to make the code do here. ph34r.gif

  • RetroRick


    QUOTE (jdiffend @ Mar 22 2007, 08:59 PM)
    However, I’d have to know how to calculate the location of the graphics screen buffer.

    For DECB, the graphics screen begins at address &H0E00 and ends at address &H3DFF. When DECB is disabled, the graphics screen begins where DECB would begin at address &H0600 and end at location &H35FF.

    There’s a PEEK value that’ll equal one value is DECB is enabled, another value if disabled. I’ll have to dig it up again. sad.gif

  • jdiffend


    QUOTE (RetroRick @ Mar 22 2007, 09:05 PM)
    I think I’ve figured out what’s wrong in the DEFEND4 code;  there’s two lines that seem to reference the incorrect variables.


    CODE
    81 IF ADR<>16316 THEN READX:FOR I=1 TO X:READ Y,Z:NEXT:RETURN

    This reads two numbers from the DATA statements into variables X and Y for each count in a FOR/NEXT loop using the I variable … and no POKE commands appear at all in this loop.

    CODE
    82 READX:FORI=1 TO X:READ Y,Z:POKE ADR+Y,Z:NEXT:RETURN

    This line reads two numbers into variables X and Y once again for each count of I’s FOR/NEXT loop, then POKEs in ADR+Y,Z.  It’s I that’s being incremented, not Y, whose value equals whatever was stored into it when reading a value from the DATA statements.

    I’d post a correction, but I’m not really sure what exactly you were trying to make the code do here.  ph34r.gif


    LOL… you just don’t understand what it’s doing.

    Line 81 is correct.
    It’s there to read through the DECB patch data if it’s run on a non-disk system so that when the rest of the program READs, it gets the proper data. It’s really just skipping what line 82 uses.

    Line 82 is correct.
    It is using the loop counter to read the number of patches specified and the next two variables are the offset in the USR function to patch and the patch itself. This modifies the ECB version (default) to a DECB version. As long as I got the correct offsets, the resulting USR1 function will work the same as if it were written just for DECB.

    Those lines were added to make it run on both ECB or DECB. I could shorten the patch at the expense of longer execution time for the USR1 routine. Since this only runs at startup I felt this was the better option.

    The problem will be with the existing code which didn’t work when I got it. Even the actual USR function is the same as the original with the exception of the speedup provided by Robert. It saves several clock cycles per loop.

  • RetroRick

    PEEK &HBC (or 188) will equal &H0E (or 14) for a disk system and 6 for non-DECB.

    BTW, I tried DEFEND2 with the ML data stored in a string. It actually does take less space overall, but then Line 39 won’t run right no matter what I do to it. Not only that, the string ML$ (which has the data for the USR routines) keeps having Byte #2 and #3 of its string changed to “*NEW”, and USR1, Joystk(2) and Joystk(3) stop working entirely. I haven’t the foggiest idea why.


    CODE
    4 ML$=”AD9FA0A4FF615D7EB4F4108E21DF10BF3FE28E21C0C61A684B73FE13AA684A71FBC3FE226F6B63FE1A7841E12C6203AC611E1210BF3FE23A8C23C026D939″
    5 L=1:DEFUSR0=474:DEFUSR1=490:FORX=474TO484:POKEX,VAL(“&H”+MID$(ML$,L,2)):L=L+2:POKEX,Y:NEXT:FORT=490TO542:POKET,VAL(“&H”+MID$(ML$,L,2)):L=L+2:NEXT
  • jdiffend


    QUOTE
    There’s a PEEK value that’ll equal one value is DECB is enabled, another value if disabled.  I’ll have to dig it up again.  sad.gif

    That would really help since I hard coded a patch for the BASIC code with what should be the new screen offset… which would cause it to fail on a cassette system.

    This would be much easier in a different language.

  • jdiffend

    Tell you what… I have another project I have to work on so it will be done by CoCo Fest.

    I’ll see about fixing the 1 hard coded patch I made to BASIC so that it will work based on the detected system. Then I’ll have to focus on the other project for a while but you should be able to use that as an example to modify any BASIC POKEs to video RAM. Once the other project is done I’ll come back and see if I can figure out what is going on. I have a hunch that the BASIC code is overwriting low memory in places and the USR1 function is trashing higher memory. I can’t be certain though.

  • RetroRick

    Thanks, man. Waiting’s no problem, since I’m balancing more than one project at the same time myself. I guess when I posted the code to the forum, I started an epidemic or something here … ph34r.gif