Jump to content
IGNORED

1050 ROMs


tregare

Recommended Posts

 

I've been working on a tool to help reverse-engineer 6502 roms. It's a long way from being finished but it can produce a code/data segments report that can help with this sort of thing. Attached are reports for the J, K and L revisions. There's an attempt to identify each separate segment of code or data based on a few heuristics and then each one is fingerprinted to help identify code that's common to multiple sets. It also attempts to recognize "dark code" segments that may be unused or called by non-standard means.

 

A few more for comparison.

1050-revH.rom.seg.txt

WSTR5.rom.seg.txt

FLOPOS.rom.seg.txt

  • Like 2
Link to comment
Share on other sites

PAGE 4   ATARI 1050 DISK DRIVE OS                                              D8:FLOPOS1.M65

F07A 2091F1     2130     JSR DELAY1  ; wait another time
F07D AD0004     2140     LDA FCNTRL
F080 2901       2150     AND #1      ; now it must by ok
F082 D019       2160     BNE FAIL    ; otherwise it't wrong
F084 A9F0       2170     LDA #$F0    ; get checksum of PROM
F086 8501       2180     STA SEKBUF+1 ; start address
F088 A900       2190     LDA #0
F08A 8500       2200     STA SEKBUF
F08C 18         2210     CLC 
F08D A8         2220     TAY 
F08E            2230 PCHECK
F08E 7100       2240     ADC (SEKBUF),Y ; add PROM bytes
F090 C8         2250     INY 
F091 D0FB       2260     BNE PCHECK
F093 E601       2270     INC SEKBUF+1 ; next page
F095 D0F7       2280     BNE PCHECK
F097 0900       2290     ORA #0      ; result must be zero
F099 8500       2300     STA SEKBUF
F09B F001       2310     BEQ TSTOK   ; if so, everything is fine
                2320 ; 
                2330 ; fatal error, break
                2340 ; 
F09D            2350 FAIL
F09D 00         2360     BRK         ; hardware defect
                2370 ; 
                2380 ; hardware test ok, do RAM test
                2390 ; 
F09E            2400 TSTOK
F09E A200       2410     LDX #0      ; write to RAM
F0A0            2420 RAMTST
F0A0 8A         2430     TXA 
F0A1 9500       2440     STA SEKBUF,X
F0A3 E8         2450     INX 
F0A4 D0FA       2460     BNE RAMTST
OS ROM test begins at line 2170 with actual rom address

of 0xF084. But the 8 bit checksum of the FLOPOS.ROM project

is 0xF1 and will fail this test for zero checksum.

 

Maybe it's defeated and made irrelevant in this manner?

Maybe I don't understand?

 

I did 8 bit checksum on the roms posted in #13 and none

of them are zero checksum either so I don't think this

section of code could ever work as designed...

 

So they all pile up on the BRK instruction at line 2360?

I am to understand that we have a bug with the BRK

instruction, it does not operate as designed is about

all I've been able to gather despite reading about

it a lot.

 

http://atariage.com/forums/topic/273221-dd-disc-track-structure-kryoflux-image/?do=findComment&comment=3917681

 

 

 

Embarassing 6502 math question... how can you keep doing an ADC on every byte in the ROM? A is only 8bits, even with the C flag (and/or V) so A will eventually be filled with FF+C, even with 2's complement math you run into a similar issue. Maybe I'm just confused :)

Link to comment
Share on other sites

 

 

Embarassing 6502 math question... how can you keep doing an ADC on every byte in the ROM? A is only 8bits, even with the C flag (and/or V) so A will eventually be filled with FF+C, even with 2's complement math you run into a similar issue. Maybe I'm just confused :)

 

Don't be embarrassed it's a perfectly reasonable question. The high order bytes are discarded. The catch is checksums aren't perfect. For 8-bit ones given any two sets of data there's a 1 in 256 chance (or something like that) that they will be falsely calculated as identical. So there's a small chance that there could be a ROM bit failure that's not detected. But apparently that's "good enough" for a consumer device such as this. An alternative to ADC could have been EOR since XOR is commonly used for simple checksums. Maybe the extra carry bit of ADC in the equation decreases the error chance a modicum over XORing?

Link to comment
Share on other sites

 

Don't be embarrassed it's a perfectly reasonable question. The high order bytes are discarded. The catch is checksums aren't perfect. For 8-bit ones given any two sets of data there's a 1 in 256 chance (or something like that) that they will be falsely calculated as identical. So there's a small chance that there could be a ROM bit failure that's not detected. But apparently that's "good enough" for a consumer device such as this. An alternative to ADC could have been EOR since XOR is commonly used for simple checksums. Maybe the extra carry bit of ADC in the equation decreases the error chance a modicum over XORing?

 

So writing a script that just adds up every byte in the ROM, constantly rolling over and taking a look at the LAST two additions (C is cleared when result is 0-255) to see if C is set is all thats needed to validate? Seems a bit wonky, but I'll roll with it.

Link to comment
Share on other sites

 

So writing a script that just adds up every byte in the ROM, constantly rolling over and taking a look at the LAST two additions (C is cleared when result is 0-255) to see if C is set is all thats needed to validate? Seems a bit wonky, but I'll roll with it.

 

Well you want to add up every byte tracking the carry bit and adding it in appropriately. In C it would look something like this

    unsigned char acc = 0;
    unsigned char carry = 0;
    short sum = 0;
    for (int i = 0; i < 0x1000; ++i)
    {
        sum = acc + data[i] + carry;
        carry = (sum > 0xFF) ? 1 : 0;
        acc = sum & 0xFF;
    }

When I run this against the ROMs discussed here the only ones that pass the checksum (i.e. final acc == 0) are revK and revL. revH, revJ, FLOPOS and WSTR5 do not. WSTR5 may be excused because it was hacked to NOP the Z flag-setting comparison opcode of the checksum (ORA #0), so it passes checksum by virtue of the preceding INC opcode clearing Z (the devs exploited this). revJ and revH are excused because their checksums are BUGGED having no accumulator comparison opcode and end up passing for the same reason that WSTR5 does (the devs apparently unaware of this and were relying on the ADC Z flag setting). That leaves only FLOPOS with no excuses, which leads me to believe that it was never actually run on a 1050.

Link to comment
Share on other sites

 

Well you want to add up every byte tracking the carry bit and adding it in appropriately. In C it would look something like this

    unsigned char acc = 0;
    unsigned char carry = 0;
    short sum = 0;
    for (int i = 0; i < 0x1000; ++i)
    {
        sum = acc + data[i] + carry;
        carry = (sum > 0xFF) ? 1 : 0;
        acc = sum & 0xFF;
    }

When I run this against the ROMs discussed here the only ones that pass the checksum (i.e. final acc == 0) are revK and revL. revH, revJ, FLOPOS and WSTR5 do not. WSTR5 may be excused because it was hacked to NOP the Z flag-setting comparison opcode of the checksum (ORA #0), so it passes checksum by virtue of the preceding INC opcode clearing Z (the devs exploited this). revJ and revH are excused because their checksums are BUGGED having no accumulator comparison opcode and end up passing for the same reason that WSTR5 does (the devs apparently unaware of this and were relying on the ADC Z flag setting). That leaves only FLOPOS with no excuses, which leads me to believe that it was never actually run on a 1050.

 

 

Wait, that's where I get lost. ADC will always set the C up or down depending on the condition of the add, ignoring if it was already set or not so why am I tracking it? Or is that wrong...

The fact that your code computes a legit checksum however has me wondering if all the 8 bit checksum programs and my own little one are completely wrong.

Link to comment
Share on other sites

This type of checksum is known as a one's complement sum. It's effectively a mod by 255 as the result will always be within $01 to $FF unless the source data is all zeroes. From a sum of all bytes where at least one byte is nonzero, the 1's complement sum is ((sum(bytes) - 1) mod 255) + 1. Using 255 instead of 256 has some advantages, like not missing an even number of errors in bit 7.

 

Note that the 1050's checksum routine is missing a final ADC #0, so even in rev. L it's still slightly broken and not quite the same as the SIO checksum.

  • Like 1
Link to comment
Share on other sites

This type of checksum is known as a one's complement sum. It's effectively a mod by 255 as the result will always be within $01 to $FF unless the source data is all zeroes. From a sum of all bytes where at least one byte is nonzero, the 1's complement sum is ((sum(bytes) - 1) mod 255) + 1. Using 255 instead of 256 has some advantages, like not missing an even number of errors in bit 7.

 

Note that the 1050's checksum routine is missing a final ADC #0, so even in rev. L it's still slightly broken and not quite the same as the SIO checksum.

 

 

Wow. Then all those 8bit checksum programs are wrong. Here is what I was missing, for those following along (as if you really care LOL)... The ADC adds the current contents of A, the memory location and also the value of 1 if the C flag is set. This last part I completely missed and isn't expressly called out in most online documentation "describing" ADC, but is quite annoying called out in the book "Assembly Language Programming for the Atari Computers". And since ORA ignores the C flag in its ORing, the "K" code checksum passes since C was set. It all becomes clear now :)

 

Thank you! The last ML coding I did was at University on an IBM 370 or 390... can't remember which. I should probably dig out my 3" thick book on C Algorithms too. LOL.

Link to comment
Share on other sites

 

 

Wait, that's where I get lost. ADC will always set the C up or down depending on the condition of the add, ignoring if it was already set or not so why am I tracking it? Or is that wrong...

The fact that your code computes a legit checksum however has me wondering if all the 8 bit checksum programs and my own little one are completely wrong.

 

You may be overthinking it a bit. A checksum is just a fancy term for a hash code where a hash is just a way to reduce a large number into a smaller number that is as unique as possible. With the idea that if two hash codes are identical then there's a high probability that they were reduced from the same large number. In the case of the 1050 the large number is 32,768 bits wide or the set of all bits of the rom. The challenge is to reduce that to an 8 bit wide hash code. Which is almost laughable, but maybe not unreasonable for an 8-bit floppy drive with less than 256 bytes of ram to work with. There are any number of ways that could have been done since all that matters is that it's relatively fast and the end result is as unique as possible. The 1050 engineers decided to use the ADC operation as their algorithm. They could've also used the EOR operation with similar results since ADDs and XORs are closely related. Or maybe 9-bit CRC. The important thing is that you don't really have to understand the algorithms used as long as you apply them consistently. ADC is a little bit tricky because of the carry-around so if those checksum programs aren't taking that into consideration then they are essentially using a different hash algorithm.

Link to comment
Share on other sites

This type of checksum is known as a one's complement sum. It's effectively a mod by 255 as the result will always be within $01 to $FF unless the source data is all zeroes. From a sum of all bytes where at least one byte is nonzero, the 1's complement sum is ((sum(bytes) - 1) mod 255) + 1. Using 255 instead of 256 has some advantages, like not missing an even number of errors in bit 7.

 

Note that the 1050's checksum routine is missing a final ADC #0, so even in rev. L it's still slightly broken and not quite the same as the SIO checksum.

 

You're correct from the perspective of doing signed math, but as I pointed out in the previous post that's not what's really going on. The checksum logic is just computing a hash code of the rom contents. So the final carry bit being lost is not an issue as long as all checksum computations do it. I didn't know that formula though, thanks for that.

Link to comment
Share on other sites

Just to be clear with everyone, my misunderstanding and math errors occurred because of how ADC is defined in most places I looked. Basically almost everything I read stated that adc adds two umbers and sets the carry flag up or down. Great. Not much said that adc is actually the value of the carry bit plus the two numbers and then the flag is adjusted up or down. In my poor mental world that meant I better use or store (in two bytes) the result of the add before doing another or the msb is lost so why should I track it at all if its only ever used after a sum (not before - which it actually is). Trust me I feel dumb for not getting that.

 

The checksum makes perfect sense once I grasped that adc is c+a+value and then set c. That one little value of 1added over and over as needed makes the check work. It didnt help that several 8-Bit math calculators I used online did not work this way and reenforced my misunderstanding.

 

Now how do you calculate the checksum value to store in the code w/o manually figuring it out. Its easy to manually guess and figure it out now but something Mathematical would be better.

  • Like 2
Link to comment
Share on other sites

This of course is another case of a lost piece of information and the understanding needed to make it work in the real world again. Please distill it into a form for all and have that re propagated into the wild, a note such as this would be well served into one of the Phaeron nuggets of knowledge papers.

Link to comment
Share on other sites

Just to be clear with everyone, my misunderstanding and math errors occurred because of how ADC is defined in most places I looked. Basically almost everything I read stated that adc adds two umbers and sets the carry flag up or down. Great. Not much said that adc is actually the value of the carry bit plus the two numbers and then the flag is adjusted up or down. In my poor mental world that meant I better use or store (in two bytes) the result of the add before doing another or the msb is lost so why should I track it at all if its only ever used after a sum (not before - which it actually is). Trust me I feel dumb for not getting that.

 

The checksum makes perfect sense once I grasped that adc is c+a+value and then set c. That one little value of 1added over and over as needed makes the check work. It didnt help that several 8-Bit math calculators I used online did not work this way and reenforced my misunderstanding.

 

Now how do you calculate the checksum value to store in the code w/o manually figuring it out. Its easy to manually guess and figure it out now but something Mathematical would be better.

 

The checksum salt is at location $F004 so injecting it into the rom data would look like

        unsigned char acc = 0;
        unsigned char carry = 0;
        short sum = 0;
        unsigned char salt;
        for (int i = 0; i < 0x1000; ++i)
        {
            // skip location of salt:
            if (i == 4)
                continue;

            sum = acc + data[i] + carry;
            carry = (sum > 0xFF) ? 1 : 0;
            acc = sum & 0xFF;
        }
        salt = 0xFF - acc;
        data[4] = salt;
Link to comment
Share on other sites

This of course is another case of a lost piece of information and the understanding needed to make it work in the real world again. Please distill it into a form for all and have that re propagated into the wild, a note such as this would be well served into one of the Phaeron nuggets of knowledge papers.

 

 

I'm not sure this is nugget of information that is lost, just something I overlooked, perhaps, when reading about ADC. Most online references, only make mention of the carry bit being set, not that it was used in the actual computation.

 

Direct from the MCS6500 MOS programming manual:

 

"This instruction adds the value of memory and carry from the previous operation [emphasis mine] to the value of the accumulator and stores that result in the accumulator.

The symbolic representation for this instruction is: A + M + C -> A"

 

All I can say is that its really good to have copies of these very old books.

  • Like 3
Link to comment
Share on other sites

 

 

I'm not sure this is nugget of information that is lost, just something I overlooked, perhaps, when reading about ADC. Most online references, only make mention of the carry bit being set, not that it was used in the actual computation.

 

Direct from the MCS6500 MOS programming manual:

 

"This instruction adds the value of memory and carry from the previous operation [emphasis mine] to the value of the accumulator and stores that result in the accumulator.

The symbolic representation for this instruction is: A + M + C -> A"

 

All I can say is that its really good to have copies of these very old books.

Odd that many books wouldn't mention it. Most that I read clearly stated that before using the add instruction, you have to clear the carry, and before subtract you have to set it for accurate results.

 

Cool that it was figured out though. That's why I love these forums, there's a wealth of information and also, many people willing to share that information. Let's keep those 6502s humming :)

  • Like 2
Link to comment
Share on other sites

This of course is another case of a lost piece of information and the understanding needed to make it work in the real world again. Please distill it into a form for all and have that re propagated into the wild, a note such as this would be well served into one of the Phaeron nuggets of knowledge papers.

 

 

You're absolutely right Doctor. Here's is my contribution to this effort.

Atari 1050 ROM Checksum Study
October 2018 atariage.com:dhinson919

Below are the results of an investigation into the Atari 1050 ROM checksum routine.  Rumors abound
that it is broken and many of them are correct, however it depends on which ROM is in use.  Some of
the accusations are incorrect based on a few simple misunderstandings and that has led to an aura
of mystery surrounding the otherwise unremarkable 15-instruction sequence of opcodes. 

In summary, later revisions of the Atari production ROM checksum correctly as designed.  However
earlier revisions do not but then “fail to fail” as designed due to a bug in the checksum subroutine.
One later production ROM shows evidence of intentional sabotaging of the routine.  Still another
community-supplied ROM simply fails due to an incorrect checksum salt.

Table 1 contains information about the ROMs studied.  Figure 1 shows the C language pseudo-code for
the checksum routine used by the study.  Table 2 shows the checksum findings.  Table 3 compares the
instructions of the various checksum routines side-by-side.  The reasons some of the routines fail
to work correctly are explained.  Finally, a few myths busted by this study are discussed.


Table 1: Source Files
Nickname  File           MD5
--------  -------------  --------------------------------
revH      1050-revH.rom  ab79b267f5e7ea2c9acbd45e1f4fbd57
revJ      1050-revJ.rom  dd296b6e2aacfd89cc94cc7e6dcebfd3
revK      1050-revK.rom  5acf59fff75d36a079771b34d7c7d349
revL      1050-revL.rom  2575d0514c5fe2dd6f5bd3f0ec434eb7
WSTR5     WSTR5.rom      5754ab8bef5c93e0caf17425d96bd80e
FLOPOS    FLOPOS.rom     ad4b6ec7de5f3fe165df02d832e31be4


Figure 1: 1050 Checksum Algorithm
    short sum;
    unsigned char A = 0; // accumulator
    unsigned char C = 0; // carry bit
    for (int offset = 0; offset < 0x1000; ++offset)
    {
        sum = A + data[offset] + C;
        A = sum & 0xFF;
        C = (sum > 0xFF) ? 1 : 0;
    }
    assert(A == 0);


Table 2: Checksum Findings
          Found           Correct         Calculated
Nickname  Checksum Salt*  Checksum Salt*  Checksum
--------  --------------  --------------  ----------
revH      $F6             $F7             $FE = FAIL
revJ      $F6             $CE             $28 = FAIL
revK      $57             $57             $00 = PASS
revL      $38             $38             $00 = PASS
WSTR5     $46             $61             $E4 = FAIL
FLOPOS    $57             $FA             $5C = FAIL
  * Checksum salt location = $F004


Table 3: Checksum Routines Compared
                      revK, revL &
      revH & revJ     FLOPOS          WSTR5           
      --------------  --------------  --------------
F084  LDA #$F0        LDA #$F0        LDA #$F0      
F086  STA $01         STA $01         STA $01       
F088  LDA #0          LDA #0          LDA #0        
F08A  STA SEKBUF      STA SEKBUF      STA SEKBUF    
F08C  CLC             CLC             CLC           
F08D  TAY             TAY             TAY           
F08E  ADC (SEKBUF),Y  ADC (SEKBUF),Y  ADC (SEKBUF),Y
F090  INY             INY             INY           
F091  BNE $F08E       BNE $F08E       BNE $F08E     
F093  INC $01         INC $01         INC $01       
F095  BNE $F08E       BNE $F08E       BNE $F08E     
F097  STA SEKBUF      ORA #0          NOP           
F098                                  NOP
F099  BEQ $F09C       STA SEKBUF      STA SEKBUF    
F09B  BRK             BEQ $F09E       BEQ $F09E     
F09D                  BRK             BRK               


Discussion:  Why do some checksum tests pass when they should fail?
-------------------------------------------------------------------

* revH & revJ

Both of these revisions use incorrect salts, yet revJ is reported to have originated from a dump
of an early production device ROM and revH from a possible predecessor to it.  So it’s puzzling
that the checksum test would fail with revJ since devices with it worked fine in the field.  Also
curious, since it shares the same code segment and salt with revH that would indicate that the
checksum failure was potentially a long-standing problem spanning multiple production runs.  How
could that be?

It appears that a benevolent bug was in play. The BEQ instruction at F099 triggers because the Z
flag is always set due to the final INC instruction execution at F093.  Control flow passes through
the BNE at F095 unbranched because SEKBUF+1 overflows (as designed) during the final INC, setting Z.
But then there are no further instructions to evaluate the accumulator to override INC’s Z setting.
This was apparently discovered and corrected in the subsequent revisions.

* revK & revL

The bug in the prior revisions was corrected by inserting an ORA between the checksum loop and the
final branch.  Since the operand to ORA is #0 it was clearly intended just for its status flags
setting side effect.  In this case the checksum in the accumulator would’ve been tested for zero.
Thus the checksum in these revisions functions as designed.

* WSTR5

For reasons unknown the engineers of this revision reverted the bug correction applied to the
previous revisions by overwriting the ORA instruction with NOPs.  Thus the Z flag is always set at
the final BEQ due to INC’s influence as was the case with revJ, effectively ignoring the checksum
result.

This raises a couple of questions though.  It’s understandable why NOP’s would have been used to
preserve the offsets of all of the other code and data segments after this early subroutine.  But
if the intent of the engineers was to completely disable the checksum routine then why did they
not NOP the entire loop saving many processor cycles?  Or simply branch around the unwanted code
in the beginning?  Could it be that they also had a misunderstanding about the Z flag influence of
the INC and INY instructions, and about the purpose of the otherwise dubious-looking ORA #0
instruction, and thought they were instead relying on the Z flag left by the ADC as it would at
first seem reasonable to do?  If that was their intent then they may never have known that they
were actually mistaken after this patch was initially tried since it would appear to have the same
effect as a correct checksum, which in fact they did not have.  (A genuine mystery...)

* FLOPOS

The actual deployment history of this community-contributed alteration of the revK revision by
Pascher & Derks is a subject of speculation.  But it seems clear that this ROM image could have
never functioned correctly on a 1050 since it uses the “correct” checksum routine found in revK
but with an incorrect checksum salt.

Discussion:  Myths Busted
-------------------------

* Myth #1, “The BRK instruction must be buggy!”

This would’ve been a wonderful explanation, but the kind of theory that requires extraordinary
evidence which doesn’t exist and in the end it’s not needed to understand the behaviors.

* Myth #2, “The checksums only pass when running on a live 1050 due to defective chip-selected
data bus input!”

This one was a bit more plausible and I was personally intrigued by it enough to spend a few
hours mapping the chip-selects of all of the 1050s devices using schematics from both Atari and
SAMS Publishing.  Based the assumed accuracy of the published schematics I can dispel this myth.
The relevant chips can only talk to the data bus when the ROM range (A12 line) isn’t being
addressed.

* Myth #3, “Maybe Atari engineers had inside knowledge of 6502 microcode bugs and exploited them
in ways that seem like magic!”

Sadly I confess I was probably the originator of this rumor.  Speculation that was the result of
being up way too late one frustrating night pondering the seemingly enigmatic 1050 checksum.
Which was, as is often the case with sufficiently advanced technology, not mysterious at all
just misunderstood.


  • Like 4
Link to comment
Share on other sites

Note that the 1050's checksum routine is missing a final ADC #0, so even in rev. L it's still slightly broken and not quite the same as the SIO checksum.

 

 

You're correct from the perspective of doing signed math, but as I pointed out in the previous post that's not what's really going on. The checksum logic is just computing a hash code of the rom contents. So the final carry bit being lost is not an issue as long as all checksum computations do it. I didn't know that formula though, thanks for that.

 

 

Table 2: Checksum Findings
          Found           Correct         Calculated
Nickname  Checksum Salt*  Checksum Salt*  Checksum
--------  --------------  --------------  ----------
revH      $F6             $F7             $FE = FAIL
revJ      $F6             $CE             $28 = FAIL
revK      $57             $57             $00 = PASS
revL      $38             $38             $00 = PASS
WSTR5     $46             $61             $E4 = FAIL
FLOPOS    $57             $FA             $5C = FAIL
  * Checksum salt location = $F004

 

@phaeron, I believe you might have explained why the revH checksum salt was "off by 1" as shown in the table above. It appears that the code that the Atari engineers used to generate that salt did in fact use one's compliment checksumming as you explained which would've added in the remaining carry bit as a final step. The result of that calculation would be $F6 and that's what they burned. However because the checksum routine in the 1050 does not add in the final carry, which is relevant in this case, the value actually needed would have been $F7. The remarkable thing is it is all moot because the revH checksum test was broken and it appears they did not know! Since the test was broken the checksum was then never an issue for the revJ engineers which is why they didn't bother to update the $F6 from the previous revision. Only until revK was the problem noticed and instead of fixing the 1050 checksum routine they chose to modify whatever they used to generate the salt!

 

Gentlemen, thank you. This comedy of errors has all been worth the price of admission.

  • Like 4
Link to comment
Share on other sites

Gentlemen, thank you. This comedy of errors has all been worth the price of admission.

Interesting having you on board as well. Curious as

to the term you use as checksum salt though. Haven't

run into it before and wondering if the salt part of

it is an acronym perhaps? Pray tell what is it if so?

 

You seem to have discovered the location for the checksum

storage correctly too. I was disappointed to learn that

my hex editor's choice of checksum generation was so

lacking in it's description and/or methods used. The

internet was of no or little help either but by shear

luck I figured out a way to get to where I wanted to

be in the first place.

 

My choices include something called checksum-8 which

I assumed was it. I was wrong, that is only the right

portion of an uncompounded add. Truncated if you will.

checksum-16 adds two more digits to the left of the

same two right side digits. Checksum-32 gives more

digits to the left even further.

 

If you take those digits and add them to a total add

then and only then do you get the accumulated add as

done by the rolling over with carry of the A register

by relentless ADC operations - which is what I wanted.

In other words what you achieved with your C snippet

which to me is for study only since I have no idea

how to make that work for me. I do have your listed

results but I was not getting the same results until

I ran BUG/65 in an emulator using this code typed in

 

post-13325-0-87407900-1539580893.png

 

rev-J.rom was loaded to 0x7000 by the emulator monitor

previously and

G6000 @6015

was entered into BUG/65 to get 29h sitting in reg A.

Other attempts weren't necessary after I found out

how to work with checksum-32 results moar better than

the internet could describe it to me. That came as

a result when I selected all the checksums at once and

noticed that the 8 version was just the truncated form

of all those higher and they were truncated in turn as

well.

 

Oh, so those are not rolled over with carry... And the

light came on.

 

Further studies into the BRK instruction show that it's

related to power up, RESET, and NMI vectors and

behavior as well. Except the B flag is set and pushed

after the PC is pushed and the vector loaded and ran is

from FFFE-FFFF.

 

Well sir, that is the blink forever more with the busy

light routine and that clearly NEVER happens with Atari

1050 code unless there is a defective chip in the works

somewhere. So something is odd somewhere with BRK

command or the way it is meant to be used.

 

I found this on the BRK instruction to notice that our

own Rybags commented on that page.

https://www.pagetable.com/?p=410

 

This is by far more information on the BRK instruction

than I have ever seen before and yet there are also

wrong info given elsewhere. Looking over Rockwell

information I see that NMOS version ignores BRK

vector and CMOS 65Cxx version uses it instead.

 

So it never was a thing for us to be able to use.

Atari sure wrote a lot of code for a neutered instruction.

And different code could be made to same effect but they

didn't do that either. Very curious situation.

  • Like 1
Link to comment
Share on other sites

Interesting having you on board as well. Curious as

to the term you use as checksum salt though. Haven't

run into it before and wondering if the salt part of

it is an acronym perhaps? Pray tell what is it if so?

 

 

A salt is data added to other data to affect the outcome of a hash. It's usually used to make the original data less guessable but in this case it's used to make the hash result entirely guessable.

 

If you take those digits and add them to a total add

then and only then do you get the accumulated add as

done by the rolling over with carry of the A register

by relentless ADC operations - which is what I wanted.

In other words what you achieved with your C snippet

which to me is for study only since I have no idea

how to make that work for me. I do have your listed

results but I was not getting the same results until

I ran BUG/65 in an emulator using this code typed in

 

 

In your snippet I suspect the final ADC was what was originally intended in the revH (and probably earlier) code. That would make the operation a complete one's complement operation as Phaeron pointed out. It was either left out by mistake or intentionally since a final carry addition is not actually needed to hash the rom effectively. But what is needed is a zero test of A which is also what ADC provided. Not replacing it with another zero testing Z setting instruction is what broke the checksum routine.

 

So it never was a thing for us to be able to use.

Atari sure wrote a lot of code for a neutered instruction.

And different code could be made to same effect but they

didn't do that either. Very curious situation.

 

 

It seems plausible that BRK could behave differently in chips from different makers. It's not intended to be used routinely so maybe there was less concern about keeping its behavior compatible with other chips.

  • Like 1
Link to comment
Share on other sites

 

Ok, so after building some silly tables in Excel I'm 100% convinced of the following:

		STA	STATUS		;** was STA ERROR in K version           [Hmm, maybe this is right.. but.. need to validate]
                JSR     DELAY1          ; 20 ms delay after SEEK  ;** was JMP DELAY1 in K version    [Hmm.. maybe this is right]
		LDA	#0		;** was LDA #1 in K version                  [Wrong, see above post]
RSTAT		JSR	FORCE		; stop controller  ;** was JSR DFORCE in K version    [Double vs single force, wonder if there was a reason for that]
		INC	SBUF+1		;** was INC SBUF in K version                [Read routine test, VERY VERY wrong, You stored track 39 in SBUF+1, how you gonna INC that?!?]
		DEC	SBUF		;** was DEC SBUF+1 in K version              [Read routine test, VERY VERY wrong, You stored track 0 in SBUF, how you gonna DEC that?]
		INC	SBUF+1		;** was INC SBUF in K version                [Write routine test, wrong, just a copy of the above wrongness]
		DEC	SBUF		;** was DEC SBUF+1 in K version              [wrong]
		AND	#$7F		; motor on  ;** was AND #$F7 in K version    [We all agree this is wrong]

 

 

 

Looking at the code again, I'm not sure about this change for JSR DELAY1. That doesn't seem right, because DELAY1 will do a RTS which dumps you right back into this section of code and the next block of code does the IRQ to interrupt the FDC twice... which makes no sense that you would want to do that every time for any track's greater than track 20.

 

So, one last thing to investigate so we can write this whole "fixed" version off the books as being wrong. :-D

  • Like 3
Link to comment
Share on other sites

BRK doesn't differ between chips from different manufacturers. It differs between different chip models, specifically the 6502 (NMOS) vs the 65C02 (CMOS).

 

Neither the 6502 nor the 65C02 has a dedicated BRK vector -- they reuse the IRQ vector for it. The sharing of the same vector is where the issue with the NMOS 6502 occurs -- essentially, an interrupt arriving at the right time can hijack a BRK instruction sequence and take it over. This then either causes the BRK to be lost or makes it at least more expensive to distinguish. The CMOS 65C02 version prevents the interrupt from overlapping the BRK instruction so the BRK is guaranteed to execute separately from interrupts. It's still expensive to separate BRK cleanly, just less so, which is why the 65C816 added a separate BRK vector entirely.

 

That having been said, the 1050 uses a 6507 instead of a 6502. The 6507 doesn't have this problem of BRK conflicting with interrupts because it has no interrupts -- the pins for them aren't connected. This means that software is free to use BRK as a one-byte subroutine call, which the 1050 does by routing BRK to the 'epic fail' routine.

  • Like 3
Link to comment
Share on other sites

I received DavidMil's 1050 'Rev H' chip today, dropped it in my EPROM programmer, dumped it, and verified that the binary matches the one I patched in post #73. (CRC32 6D9D589B) The first byte was indeed $FB as I predicted like Rev J, K, L, and the rest of the bytes were consistent with the previous dump:

post-53052-0-61521800-1539930173_thumb.png

and at offset 0FFH you can see the "H" version byte:

post-53052-0-89046900-1539930187_thumb.png

I also took some high res macro shots of this particular chip and its label.

post-53052-0-03380800-1539930321_thumb.jpg

I didn't notice this before, but if you look closely it appears there is a letter "H" written with a red ball-point pen on the end of the label. I took another macro shot, with a flashlight lighting from the side to highlight the texture of the label, which help make the "H" more visible! Corroborates the "H" found in the dump.

post-53052-0-57081100-1539930349_thumb.jpg

I'd like to know if this version has any differences that would cause copy protection checks to behave differently than J/K/L. But maybe that behaviour is only a trait of the fabled Rev E/F. Search is now on for those! :)

  • Like 6
Link to comment
Share on other sites

The only difference between H and J other than the revision code is a curious change in the subroutine known as RDBYTE in the P&D annotation (see bottom). This is where the CPU works with the RIOT chip to read in a byte from the SIO port. Two locations that are NOPs in H are replaced with a LSR $B6 in J. The reason that's curious is that $B6 does not appear to have any other use in the ROM code. It would be equivalent to SBUF+5 in the P&D. SBUF is on the tail end of the used RIOT RAM. SBUF, SBUF+1 and SBUF+2 are mentioned in P&D but nothing past that. I've also confirmed using a different disassembly that location $B6 isn't used anywhere else.

 

So what's going on? It could be debugging code. That the instruction replaces NOPs suggests that the NOPs may have replaced this instruction originally in a prior revision in order to disable it but then it was reinstated in J. The LSR of $B6 would happen every time a byte was read from the RIOT (/SIO port). Why would one bother to right-shift a location that isn't read anywhere else? Well if you had a test jig that allowed you to inject a value into that RIOT RAM location then you could use the changing bit pattern resulting from the LSR to gate some other external logic that supplies test input to the SIO. For example if you wanted to gate the input for 8 byte read cycles you would inject $FF. 4 byte read cycles would be $0F. Alternating byte cycles would look like $55. Etc.

 

Or it could simply be a way to delay 1 extra clock cycle in this time-sensitive code by converting 2 NOPs (4 cycles) to a LSR of an otherwise unused address (5 cycles).

 

Both seem a bit dubious to be honest but it's the only theories I have at the moment.

      revH          revJ
      ----------    ----------
F3D1  STX $B3
F3D3  BIT DRA
F3D6  BVC $F3FD
F3D8  BIT DRB
F3DB  BVC $F3D3
F3DD  SEC
F3DE  LDA #$80
F3E0  LDX #5
F3E2  DEX
F3E3  BNE $F3E2
F3E5  LDX #6
F3E7  DEX
F3E8  BNE $F3E7
F3EA  NOP           LSR $B6
F3EB  NOP           "
F3EC  BIT DRB
F3EF  BVC $F3F4
F3F1  CLC
F3F2  BCC $F3F6
F3F4  SEC
F3F5  NOP
F3F6  ROR A
F3F7  BCC $F3E5
F3F9  TAY
F3FA  LDX $B3
F3FC  RTS

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...