diff --git a/cardBase.go b/cardBase.go index 7c1cdaf..ac3eeb2 100644 --- a/cardBase.go +++ b/cardBase.go @@ -44,7 +44,6 @@ func (c *cardBase) assign(a *Apple2, slot int) { if slot != 0 { if c.romCsxx != nil { // Relocate to the assigned slot - //c.romCsxx.base = uint16(0xc000 + slot*0x100) c.romCsxx.setBase(uint16(0xc000 + slot*0x100)) a.mmu.setCardROM(slot, c.romCsxx) } diff --git a/diskette16sector.go b/diskette16sector.go index ada315c..43312a8 100644 --- a/diskette16sector.go +++ b/diskette16sector.go @@ -11,12 +11,6 @@ type diskette16sector struct { position int } -func newDisquette16Sector(f *fileNib) *diskette16sector { - var d diskette16sector - d.nib = f - return &d -} - func (d *diskette16sector) powerOn(cycle uint64) { // Not used } diff --git a/diskette16sectorTimed.go b/diskette16sectorTimed.go index a3df441..65985cb 100644 --- a/diskette16sectorTimed.go +++ b/diskette16sectorTimed.go @@ -5,12 +5,6 @@ type diskette16sectorTimed struct { cycleOn uint64 // Cycle when the disk was last turned on } -func newDisquette16SectorTimed(f *fileNib) *diskette16sectorTimed { - var d diskette16sectorTimed - d.nib = f - return &d -} - func (d *diskette16sectorTimed) powerOn(cycle uint64) { d.cycleOn = cycle } diff --git a/fileNib.go b/fileNib.go index 7bcc7d6..039735f 100644 --- a/fileNib.go +++ b/fileNib.go @@ -1,6 +1,8 @@ package apple2 import ( + "errors" + "fmt" "os" ) @@ -100,6 +102,25 @@ var sixAndTwoTranslateTable = [0x40]byte{ 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, } +var sixAndTwoUntranslateTable = [256]int16{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, 2, 3, -1, 4, 5, 6, + -1, -1, -1, -1, -1, -1, 7, 8, -1, -1, -1, 9, 10, 11, 12, 13, + -1, -1, 14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, 26, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, 28, 29, 30, + -1, -1, -1, 31, -1, -1, 32, 33, -1, 34, 35, 36, 37, 38, 39, 40, + -1, -1, -1, -1, -1, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, + -1, -1, 51, 52, 53, 54, 55, 56, -1, 57, 58, 59, 60, 61, 62, 63, +} + const ( gap1Len = 48 gap2Len = 5 @@ -112,8 +133,8 @@ func oddEvenEncodeByte(b byte) []byte { A byte is encoded in two bytes to make sure the bytes start with 1 and does not have two consecutive zeros. Data byte: D7-D6-D5-D4-D3-D2-D1-D0 - resutl[0]: 1-D7- 1-D5- 1-D3-1 -D1 - resutl[1]: 1-D6- 1-D4- 1-D2-1 -D0 + result[0]: 1-D7- 1-D5- 1-D3- 1-D1 + result[1]: 1-D6- 1-D4- 1-D2- 1-D0 */ e := make([]byte, 2) e[0] = ((b >> 1) & 0x55) | 0xaa @@ -121,6 +142,24 @@ func oddEvenEncodeByte(b byte) []byte { return e } +func oddEvenDecodeByte(b0, b1 byte) byte { + /* + A byte is encoded in two bytes to make sure the bytes start with 1 and + does not have two consecutive zeros. + b0: 1-D7- 1-D5- 1-D3- 1-D1 + b1: 1-D6- 1-D4- 1-D2- 1-D0 + result: D7-D6-D5-D4-D3-D2-D1-D0 + */ + return ((b0 & 0x55) << 1) | (b1 & 0x55) +} + +const ( + diskPrologByte1 = uint8(0xd5) + diskPrologByte2 = uint8(0xaa) + diskPrologByte3Address = uint8(0x96) + diskPrologByte3Data = uint8(0xad) +) + func nibEncodeTrack(data []byte, volume byte, track byte, logicalOrder *[16]int) []byte { b := make([]byte, 0, nibBytesPerTrack) // Buffer slice with enough capacity // Initialize gaps to be copied for each sector @@ -135,7 +174,7 @@ func nibEncodeTrack(data []byte, volume byte, track byte, logicalOrder *[16]int) for physicalSector := byte(0); physicalSector < numberOfSectors; physicalSector++ { /* On the DSK file the sectors are in DOS3.3 logical order but on the physical encoded track as well as in the nib - files they are in phisical order. + files they are in physical order. */ logicalSector := logicalOrder[physicalSector] sectorData := data[logicalSector*bytesPerSector : (logicalSector+1)*bytesPerSector] @@ -181,3 +220,76 @@ func nibEncodeTrack(data []byte, volume byte, track byte, logicalOrder *[16]int) return b } + +func findProlog(diskPrologByte3 uint8, data []byte, position int) int { + l := len(data) + for i := position; i < l; i++ { + if (data[i] == diskPrologByte1) && + (data[(i+1)%l] == diskPrologByte2) && + (data[(i+2)%l] == diskPrologByte3) { + + return (i + 3) % l + } + } + + return -1 +} + +func nibDecodeTrack(data []byte, track byte, logicalOrder *[16]int) ([]byte, error) { + b := make([]byte, bytesPerTrack) // Buffer slice with enough capacity + + i := int(0) + l := len(data) + + for { + // Find address field prolog + i = findProlog(diskPrologByte3Address, data, i) + if i == -1 { + break + } + // We just want the sector from the address field, we ignore the rest, no error detection + sector := oddEvenDecodeByte(data[(i+4)%l], data[(i+5)%l]) + logicalSector := logicalOrder[sector] + dst := int(logicalSector) * bytesPerSector + fmt.Printf("Processing sector %v (%v), destination: %v\n", sector, logicalSector, dst) + + i = (i + 8 + 3) % l // We skip the four two byte fields and the epilog + + // Find data prolog + i = findProlog(diskPrologByte3Data, data, i) + + // Read secondary buffer + prevV := byte(0) + for j := 0; j < secondaryBufferSize; j++ { + w := sixAndTwoUntranslateTable[data[i%l]] + if w == -1 { + return nil, errors.New("Invalid byte from nib data") + } + v := byte(w) ^ prevV + prevV = v + for k := 0; k < 3; k++ { + // The elements of the secondary buffer add two bits to three bytes + offset := j + k*secondaryBufferSize + if offset < bytesPerSector { + b[dst+offset] |= ((v & 0x02) >> 1) | ((v & 0x01) << 1) + } + v >>= 2 + } + i++ + } + + // Read primary buffer + for j := 0; j < primaryBufferSize; j++ { + w := sixAndTwoUntranslateTable[data[i%l]] + if w == -1 { + return nil, errors.New("Invalid byte from nib data") + } + v := byte(w) ^ prevV + b[dst+j] |= v << 2 // The elements of the secondary buffer are the 6 MSB bits + prevV = v + i++ + } + } + + return b, nil +} diff --git a/fileNib_test.go b/fileNib_test.go new file mode 100644 index 0000000..111e6f5 --- /dev/null +++ b/fileNib_test.go @@ -0,0 +1,25 @@ +package apple2 + +import ( + "testing" +) + +func TestNibBackAndForth(t *testing.T) { + // Init data + data := make([]byte, bytesPerTrack) + for i := 0; i < bytesPerTrack; i++ { + data[i] = byte(i % 100) + } + + nib := nibEncodeTrack(data, 255, 0, &dos33SectorsLogicalOrder) + data2, err := nibDecodeTrack(nib, 0, &dos33SectorsLogicalOrder) + if err != nil { + t.Error(err) + } + + for i := 0; i < bytesPerTrack; i++ { + if data[i] != data2[i] { + t.Errorf("Mismatch in %v: %02x -> %02x", i, data[i], data2[i]) + } + } +}