简体   繁体   English

Apple IIe 6502 组件存取盘

[英]Apple IIe 6502 Assembly Accessing Disk

I'm currently writing a program for the Apple IIe that requires reading/writing files from disk.我目前正在为需要从磁盘读取/写入文件的 Apple IIe 编写程序。 In reading the books I've found archived online about assembly language for the Apple II I've come across the $C060 subroutine which is for accessing the cassette port, but I can't seem to find a subroutine that will access the disk drive.在阅读我在网上找到的关于 Apple II 汇编语言的书籍时,我遇到了用于访问磁带端口的$C060子程序,但我似乎找不到可以访问磁盘驱动器的子程序. Is there such a monitor command?有没有这样的监控命令? If not, what would I do to read/write a file to/from disk during the program?如果没有,我将如何在程序期间从磁盘读取/写入文件?

It's possible to read and write a floppy disk without loading in DOS.无需在 DOS 中加载就可以读写软盘。 DOS is useful if you want to read/write disks that are usable by other programs, and making things work reliably using DOS is apt to be easier than using raw I/O, but raw I/O can be faster than DOS and allow more information to be stored on a disk, especially if you never need to read or write less than a track at a time.如果你想读/写其他程序可用的磁盘,DOS 很有用,使用 DOS 使事情可靠地工作比使用原始 I/O 更容易,但原始 I/O 可以比 DOS 更快并且允许更多要存储在磁盘上的信息,特别是如果您永远不需要一次读取或写入少于一个轨道的信息。

When using track-at-a-time I/O, writing and reading a disk is conceptually simple:使用一次一个轨道的 I/O 时,写入和读取磁盘在概念上很简单:

  1. To write a disk track, build a buffer holding about 6K of suitably-formatted data, turn on the motor, move the head to the desired track, turn on the write signal, write the pattern 0x92 $A4 about 500 times [if the buffer is much smaller than 4,000 bytes, it may be necessary to increase that count, so as to write a total of at least ~5,000 bytes], followed by $9F then output the contents of the buffer and turn off the write signal.要写入磁盘磁道,建立一个缓冲区,其中包含大约 6K 的适当格式的数据,打开电机,将磁头移动到所需的磁道,打开写入信号,将模式 0x92 $A4 写入大约 500 次[如果缓冲区比 4,000 字节小得多,可能需要增加计数,以便至少写入 ~5,000 字节],然后是 $9F,然后是 output 缓冲区的内容并关闭写入信号。 Bytes must be sent to the drive controller precisely once every 32 clock cycles.必须每 32 个时钟周期将字节精确地发送到驱动器 controller 一次。 Slipping by even one cycle will cause the controller to output garbage.甚至一个周期的滑动都会导致 controller 到 output 垃圾。

  2. To read a disk track, turn on the motor, move the head to the desired track, and read bytes of data from the disk until one sees a the byte sequence $92 $A4 $9F, and then read the rest of the data.读取磁盘磁道,打开电机,将磁头移动到所需磁道,从磁盘读取数据字节,直到看到字节序列 $92 $A4 $9F,然后读取数据的 rest。 Data will arrive at a rate of about 32 cycles/byte, and each byte must be read within a 7 cycle window.数据将以大约 32 个周期/字节的速率到达,每个字节必须在 7 个周期 window 内读取。

The data read back should precisely match the data written provided every byte in the buffer upholds three restrictions:读回的数据应该与写入的数据精确匹配,前提是缓冲区中的每个字节都遵守三个限制:

  1. Every byte must have the most significant bit set.每个字节都必须设置最高有效位。

  2. No byte may contain more than two consecutive 0 bits.任何字节都不能包含两个以上连续的 0 位。

  3. Every byte must contain at least one pair of consecutive 1 bits.每个字节必须至少包含一对连续的 1 位。

There are 64 possible byte values that meet those criteria.有 64 个可能的字节值满足这些条件。 Encoding arbitrary data to fit that limitation before storing it, and decoding information that is written in that fashion can be a nuisance, but that's part of the "fun" of writing one's own disk routines.在存储之前对任意数据进行编码以适应该限制,并对以这种方式写入的信息进行解码可能会很麻烦,但这是编写自己的磁盘例程的“乐趣”的一部分。 Many disk routines read data into a buffer without decoding it, and then decode it later, but if one chooses a suitable encoding it's possible to decode information in real time as it's received from the disk.许多磁盘程序在不解码的情况下将数据读入缓冲区,然后再解码,但如果选择合适的编码,则可以在从磁盘接收到信息时实时解码。

I forgot to mention how to move the turn on the drive, select drive 1 or 2, move head, read, and write bytes from a controller in slot 6:我忘了提到如何移动驱动器 select 驱动器 1 或 2,移动磁头,从插槽 6 中的 controller 读取和写入字节:

  1. To turn on the drive, access $C0E9.要打开驱动器,请访问 $C0E9。 To turn it off, access $C0E8.要关闭它,请访问 $C0E8。 The effect of turning off the drive will be delayed by about a second.关闭驱动器的效果会延迟大约一秒钟。

  2. To switch to drive 2, access $C0EB.要切换到驱动器 2,访问 $C0EB。 To switch to drive 1, access $C0EA.要切换到驱动器 1,访问 $C0EA。

  3. To move the head, think of it as being attached to a wheel which is attached to a hand on a clock face.要移动头部,请将其视为连接到一个轮子上,而该轮子连接到钟面上的指针上。 The hand will point at 12:00 when the head is at any even numbered, track, and at 6:00 when it is on any odd numbered track.当磁头位于任何偶数轨道时,指针将指向 12:00,当磁头位于任何奇数轨道时,指针将指向 6:00。 Reading $C0E1, $C0E3, $C0E5, or $C0E7 will turn on a coil that pulls the hand toward 12:00, 3:00, 6:00, or 9:00.读取 $C0E1、$C0E3、$C0E5 或 $C0E7 将打开一个线圈,将指针拉向 12:00、3:00、6:00 或 9:00。 Accessing the next lower address will turn off the coil.访问下一个较低地址将关闭线圈。 Move the head by turning on a coil 90 degrees from the wheel's current position, waiting awhile, turning that coil off and turning on the next one, etc.通过打开与车轮电流 position 成 90 度角的线圈来移动头部,等待一会,关闭该线圈并打开下一个线圈,依此类推。

  4. To see if a drive is attached, read $C0EC a few times and see if the value changes.要查看是否连接了驱动器,请多次读取 $C0EC 并查看值是否发生变化。 If not, no drive is attached.如果不是,则没有连接驱动器。 If a drive is known to exist, use a two-instruction loop to read $C0EC until the high bit becomes set.如果已知驱动器存在,则使用双指令循环读取 $C0EC,直到设置高位。 If one a four-cycle instruction was used for the read, and a two-cycle branch-not-taken once high bit became set (eg wait293: LDX $C0EC / BPL wait293 ).如果一个四周期指令被用于读取,并且一旦高位被设置则两个周期分支不被采用(例如wait293: LDX $C0EC / BPL wait293 )。 To ensure that one reads every byte, ensure that the CPU executes at least 12 and at most 24 cycles before the next time the sequence is executed.为确保读取每个字节,请确保 CPU 在下一次执行序列之前至少执行 12 个周期,最多执行 24 个周期。 Taking less than 12 cycles may yield duplicate reads.少于 12 个循环可能会产生重复读取。 Taking more than 24 may cause bytes to be skipped.取多于 24 可能会导致跳过字节。

  5. To start writing data, write any value to $C0ED, then write the first byte value to $C0EF and immediately read $C0EC (ignore the value written).要开始写入数据,将任何值写入 $C0ED,然后将第一个字节值写入 $C0EF 并立即读取 $C0EC(忽略写入的值)。 One must then execute exactly 24 cycles of other code, a write of the next byte to $C0ED, an immediate read of $C0EC, etc. When done, read $C0EE.然后必须执行其他代码的 24 个周期,将下一个字节写入 $C0ED,立即读取 $C0EC,等等。完成后,读取 $C0EE。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM