Jump to content

RedskullDC

Members
  • Posts

    24
  • Joined

  • Last visited

Everything posted by RedskullDC

  1. Hi Nippur72, et al. Been thinking about this a bit more over the last few days..... Using the SDRAM means that you will have to allow for the refresh cycles which are quite different to the original 4164 DRAMs on the 500. With the SDRAM chip on the mist board, each refresh cycle is around 70ns as far as I can see from the datasheet, with each row needing to be refreshed at least once every 32ms IIRC. The dual port SDRAM controller would be best. You can run the video side with the 14.778730MHz clock without any problem to generate the exact PAL signal, and have a cycle exact vertical interrupt. That also allows simple modification should you decide you want to generate a VGA signal somewhere down the track. Modify the SDRAM controller so it only allows refresh cycles to occur during the non-visible parts of the screen display. (HSYNC and VSYNC active), and only during the VIDEO "slot". I don't think that the 32ms maximum refresh interval time is necessarily something to worry about too much. I've experimented in the past with delaying the refresh cycles to SDRAM chips to see how long they would retain their contents without a refresh cycle. A couple of chips were able to retain their contents reliably for anything up to 4-5 seconds without a refresh cycle being allowed to occur. Far in excess of the 32ms quoted. The CPU side of the SDRAM controller is easy, as you no longer have to interleave with the video side. As long as you insert one wait state to the Z80 for each RAM/ROM read/write, the timing should match the original machine exactly. My Laser 500 has now been shipped, so as soon as it arrives I will be able to confirm your screen calculations of 952x312 precisely. Cheers, Leslie
  2. Emulating some of the poor design decisions of early machines is not always a good idea You hobble your design with constraints to deal with hardware that isn't even there on the FPGA board. How accurate do you want to make it? --- You can easily get around the RAM bottle neck by using a dual port SDRAM controller. Check out the one used in: https://github.com/NibblesLab/mz80b_de0 It's an emulation of the SHARP MZ80B on the Terasic DE0 board. --- Nice of Platis to fill in some of the blanks! Look forward to seeing a scan of that manual! Cheers, Leslie
  3. Hi Nippur72, From an FPGA point of view, there is nothing to solve. I assume you will but the LASER ROM image inside a Block RAM on the FPGA? Use the 4 BA bits to determine which block is being accessed. Read the SDRAM and ROMs in parallel. Z80 can access the ROM, while video section reads from SDRAM. PAL screen output looks good. Cheers, Leslie
  4. I can see 250ns EPROMS are fitted in the pic above. If the ROM read cycles get the wait state the speed doesn't really matter. Read will be initiated in one CPU cycle, the ROMs will be read in the next CPU cycle. --- Yes, the LS273 will latch the output of the Character Generator. We just have no idea when in the cycles the VLSI actually reads that data. Will probably have to measure it with a scope to be sure. At a guess I would say it is read during the section you marked in blue during the video "slot". That is the only time you can guarantee that the DRAMs are not driving the RD7:0 lines. Cheers, Leslie
  5. I didn't say 8 "cycles", but 8 clock edges (both rising and falling). That gives you 8 distinct state changes within one CPU clock period. --- Delay line is probably correct for the generation of the *CAS falling edge. Data sheet for the 4164 DRAM says the max RAS to CAS delay is 75ns for the 150ns part. Period for the 14.7MHz clock is 67ns, which would be cutting it a bit close. --- That's good to know that ROM reads also get a wait state inserted, even though it isn't necessary. Regards, Leslie
  6. Timing diagram looks reasonable to me, but all guesswork till we get a scope/analyser on the real machine I've added a couple of descriptions to the pin table. Not sure what FRSEL and /TOPBK are meant to do? RAS and CAS *are* aligned to the 14MHz clock. *RAS, *CAS, *AX will all likely be generated by a state machine circuit in the VLSI chip. Looking at the timing diagram, imagine that the Video "slot" is divided into 8 distinct sections, split on each clock edge of F14M. State 0 begins at the rising edge of F14M, at the start of the video "slot" Here is what happens at each clock edge: 0: Assume that MA7:0 outputs are stable and hold the video ROW bits. *RAS goes low, clocking the ROW bits into the DRAMs. Access time for the DRAMs begins now. 1: *AX goes low. MA7:0 are now outputting the COLUMN data bits 2: *CAS goes low, clocking the column data into the DRAMs. Difficult to tell from the diagram whether CAS is generated from clock edge 2, or by a delay line attached to clock edge #1. Either would suffice. 3-4 do nothing, maintain state 5: RAS goes high 6. *CAS and *AX both go high. Video section will most likely sample RAM data here. (approx 201ns after the falling egde of *RAS) *MREQ from the Z80 may go low here if the CPU is trying to initiate a read cycle. With AX high, the multiplexers will be selecting the ROW data of the Z80 address bus in readiness for the CPU cycle. 7. do nothing, maintain state ---- CPU slot is basically the same as the video slot. All data to/from the DRAMs goes through the VLSI chip on the RD7:0 lines. Presumably, the VLSI chips latches CPU read/write data, and presents it to the CPU during the CPU slot. It doesn't appear that wait states are inserted for ROM reads or keyboard reads either? It also isn't possible to tell from the diagram when the VLSI chip reads the character generator ROM/latch (2764/74LS273). Suspect it does that during the CPU "slot" when it has free access to the RD7:0 lines. We badly need a full scan of that technical manual Cheers, Leslie
  7. VLSI chips differences are probably just batch numbers. Not sure there would be any revision differences. 17MHz crystal may only be required for the CHROMA and COLOURBURST signals? I've seen a couple of 500's with no RF modulator fitted. Not really sure of the purpose of the F3M pin on the VLSI chip. Perhaps they use it to derive a harmonic from the 14MHz crystal....?? Cheers, Leslie
  8. 4 x 14MHz cycles. My Laser 500 hasn't arrived yet. The video and cpu "slots" are both 1 CPU clock wide (3.6947MHz) or 4 x 14.77873MHz clocks wide. Period of one CPU clock at 3.6947MHz is approximately 271ns long. A pic of the 500 motherboard: https://www.flickr.com/photos/grupousuariosamstrad/7615785522 shows it to be fitted with 150ns DRAM chips. DRAMs are easily able to responding within the 271ns "slot" . Regards, Leslie
  9. Nothing you need to worry about from an FPGA point of view. AX = Address multipleX. Between the Z80 and GA1 on the schematic are 2 x 74LS257 Multiplexers. AX is connected to the Select line on both of those chips, and is used to multiplex the A15-A0 address bus down to the MA7-MA0 signals which go to the DRAMs Sequence is: 1. At the start of a video/cpu "slot", *RAS, *AX, *CAS are all high. 2. Multiplexers are currently selectin the "ROW" address bits 3. *RAS goes low, registering the ROW bits in the DRAMS 4. AX changes state, Multiplexers are now selecting the "COLUMN" address bits 5. *CAS goes low, registering the COLUMN bits in the DRAMS 6. DRAMs now have the full address information. ---- The address multiplexers only appear to be used for when the Z80 is addressing the DRAMs. GA1 has its' own MA7-MA0 outputs for when the video section is addressing the DRAMs The CVAM output from GA1 (CPU/VIDEO-ADDRESS-MULTIPLEX?) can disable the multiplexer outputs. That will be the CV signal shown in the timing diagram. ----- Interesting to see the selection of ROW bits are A0, A1, A2, A3, A4, A8, A9, A10. This means that the 7 bit refresh address generated by the Z80 is ignored completely. VIDEO section multiplexers inside GA1 must be similarly wired as the external CPU ones. I haven't checked, but I wouldn't mind betting those particular address lines cycle through all 256 combinations as a result of the screen being re-drawn, no matter what screen mode is being displayed. In effect, providing an invisible 8 bit DRAM refresh cycle Regards, Leslie
  10. That is correct, but it also gives us the answer to the reason for delay circuit! Since the F14M clock is stopped, nothing is advancing in the VLSI. The *only* effect that the delay circuit has is to stretch the HSYNC pulse by around 470ns Presumably the HSYNC pulse coming out of the VLSI chip is too short due to an error in the logic which was only discovered after the VLSI chips were already manufactured? Has the unfortunate side effect of slowing the CPU down by 470ns every horizontal line. Cheers, Leslie
  11. I don't think the one I purchased came with any manuals The auction pics show it to be a QWERTY model keyboard, with only ENGLISH keytops. Will be interesting to see if the ROMS are the same as what we already have. Definitely looking forward to a scanned copy of the BASIC manual and tech manual. They would clear up a lot of mysteries I'm sure! ---- Easiest way to implement the wait states on the 500 is to just have a circuit which inserts a one-cpu-clock wait state for every memory read/write/instruction fetch. There isn't any need to tie it to the video generation to achieve the same effect as a real machine. Better to have the video run independently, then you can have any output frequency you like. Doesn't need to be tied to the 14.7MHz clock. The digital delay line circuit introduces a ~ 473ns (1000ns/ 14.7MHz * 7 = 473ns) pause in the 14Mhz clock after every *HSYNC. If you are planning to use the same Z80 core as the LASER_310_FPGA project, it already has a clock enable input which you could use to mimic this delay. Re-creating the hardware as close as possible is a great idea. Don't think I'm trying to point you in a different direction. At some point (if you are like me) you will most likely want to extend the FPGA implementation to : a) run faster b) emulate disks/cassettes c) more memory d) extended screenmodes (such as the Laser 3000 HI-RES RGB modes) With that in mind, it is best not to cripple your video output section to mimic hardware kludges from the 1980's if you don't have to Look forward to seeing your progress! Cheers, Leslie
  12. They look like sane values to produce a PAL signal. I don't think there is any way to figure out the missing CPU signals without putting a logic analyser on a real machine. To assist with that , I just purchased a Laser 500 which I saw on Ebay: https://www.ebay.com.au/itm/202660668891 -- I wouldn't be too concerned with emulating the PAL output and memory wait states in an FPGA version. It really isn't necessary Much easier to use dual port memory for the video memory regions, and let the video and cpu run completely independently. If the machine is running a bit fast, can always lower the CPU clock. Disk system runs independently off its' own 4MHz clock, so no need to sync that. 17MHz signal is not required at all on the FPGA. If you want to use the entire screen, recommend using 1280x960 as the video output standard (4:3) On the max resolution screen (640 x 192) each horizontal pixel is displayed twice, and each vertical line is displayed 5 times. 640 x 2 = 1280, 192 * 5 = 960. Otherwise, SVGA=800x600. Multiply the vertical lines by 3 = 576. Centre the video, and display the border register colour when outside the 640x192 area. Cheers, Leslie
  13. According to the timing diagram, the CPU and VIDEO sub-section share access to the RAM memory on each alternate CPU clock cycle. A 1:1 basis. Third line of the diagram shows the CPU CK (CPU CLOCK). CPU doesn't know anything about the video section, so it can issue a memory read/write instruction fetch at *any* time, during the CPU "slot" or VIDEO "slot". You will need to take a look at a Z80 tech manual to see that each memory read/write operation takes 3 clock cycles ("T" states) and an instruction fetch takes 4. (Assuming no wait states). On a mem read/write cycle, *MREQ , *RD both go low on the falling edge of the T1 state. *WR goes low on the falling edge of the T2 state. Referring back to the Laser timing diagram, this will always be when CPU CK is LOW. There is no way of knowing if that falls in the CPU allocated slot, or the video slot. VIDEO always reads a byte in one "slot" CPU always requires two "slots". Consider for a minute that the CPU clock is 3.6947 Mhz. That means that the period of the CPU clock is somewhere close to 271ns. Plenty of time for the VIDEO section to read a byte from RAM in it's "slot". The point where the CPU asserts *RD or *WR in the cycle (3/4 of the way through the "slot") doesn't allow enough time for the RAMS to respond however. A one-cpu-clock wait state is therefore always inserted for every memory byte read, memory byte write and for each byte of the instruction fetch (including one wait state for each operand byte) regardless of which "slot" the CPU read/write is initiated in. I don't think that I/O instructions have a wait state inserted according to the diagram. --- Regarding the HSYNC. No, it's only triggered on the falling edge... according the the diagram. Cheers, Leslie
  14. Hi Nippur72, I thought about the problem some more.. It's possible that stopping the F14M clock in that position has something to do with the colour burst signal generation. Your suggestion that it may be an add-on circuit to fix a bug in the VLSI chip that was only discovered after they were produced may not be a bad guess either. I don't think that the missing cycles have anything to do with scanline dependent features. According to the timing diagram, there is a one cpu clock wait state inserted for *every* memory access, whether it be read/write/opcode fetch. Are you accounting for the instructions and overhead during the interrupt after each vertical retrace? Regards, Leslie P.S. I think it is an interesting co-incidence that the Laser 350/500/700 series employs the same control register address ($6800) as the earlier LASER 310/VZ200/VZ300 machines. The graphics/text screen layouts on the 350/500/700 are basically the same as an Apple ][. It would come as no surprise to learn that VTECH used some of the same VLSI code from their LASER 3000 series machine here. I had a quick look at the Laser 3000 tech manual, but it does not have a delay line circuit like the 350-700.
  15. Hi Nippur72, et al. 1. Not sure. 2. CPU Clock and Mem accesses are synchronised to the F14M signal. (pg 214 of the tech manual, posted in this thread) 3. The flip-flops provide a digital delay, not a divide by 4 . Pin 9 of the LS02 takes a product of the delay circuit. When pin 9 is low, F14M runs freely same as T14M, but inverted. When pin 9 is high, F14M is held low. When HSYNC goes from High to low, the circuit holds F14M low for 6 (or 7) 14Mhz clocks. When HSYNC goes from low to high, there is no delay. 4. Maybe the GA1 uses this time to reload the colour registers etc. in preparation for the next display line? Cheers, Leslie
  16. Hi Platis, Can't say that I have seen that one. Doesn't appear to be on any of the popular VZ200-300/LASER 310 repositories that I can see. No use for programming the Laser 350/500/700 models of course. Cheers, Leslie
  17. Hi Nippur72, Thanks for the debug code! That explains the code for the CTRL-1 == capslock! ----- I tried your debug code out with the "MOTOR ON" and "MOTOR OFF" commands from BASIC. They are definitely flipping bit#7 in &H6800 writes. "MOTOR ON" gives: bit 7 changed from 0 to 1 at 0f7c "MOTOR OFF" gives: bit 7 changed from 1 to 0 at 0f7c If you have a cassette recorder attached with the correct remote cable attached and the play and/or record buttons down, it should start and stop the recorder. Cheers, Leslie
  18. Hi Nippur72, et al. I was aware of it, but hadn't though to try it. Your list shows it does a pretty good job of locating most things. ---- Can I trouble you to test a couple of things on your real machine? I'm looking at Bits #6 and #7 of &H6800 on write. Bit#7 should be the cassette motor control output. Bit#6 is turned on/off by a routine which hangs off the interrupt chain if a certain key combination is pressed: SHIFT-CONTROL-1 (I think) I'm wondering if Bit#6 controls the "GT" output of the gate array, which is connected to the character generator? If so, it may switch visible character sets on machines which have CGA11 and CGA12 correctly jumpered? Cheers, Leslie RAM:0A56 sub_A56: ; CODE XREF: RAM:0A1A↑p RAM:0A56 RAM:0A56 ; FUNCTION CHUNK AT RAM:0AD3 SIZE 0000000B BYTES RAM:0A56 RAM:0A56 06 02 ld b, 2 ; Bring in I/O Bank RAM:0A58 CD E5 0A call SET_BANK1_B ; set Bank#1 to value in B reg, save old on stack, and return RAM:0A5B 21 FF 6A ld hl, 6AFFh ; Keyboard row 'C'? RAM:0A5E CB 76 bit 6, (hl) ; check CAPS LOCK ? RAM:0A60 28 11 jr z, loc_A73 RAM:0A62 CD A3 0A call CHECK_CONTROL_KEY ; check if control key is down - ZERO if true RAM:0A65 20 2F jr nz, loc_A96 RAM:0A67 21 F7 6F ld hl, 6FF7h ; check Row KA3 RAM:0A6A CB 6E bit 5, (hl) ; bit 5 = '1' key? RAM:0A6C 20 28 jr nz, loc_A96 RAM:0A6E 3E 3F ld a, 3Fh ; '?' RAM:0A70 32 F0 85 ld (byte_85F0), a RAM:0A73 RAM:0A73 loc_A73: ; CODE XREF: sub_A56+A↑j RAM:0A73 21 FB 85 ld hl, operation_flags2 RAM:0A76 CB 6E bit 5, (hl) RAM:0A78 20 21 jr nz, loc_A9B RAM:0A7A CB EE set 5, (hl) RAM:0A7C 3A F9 85 ld a, (REG_6800W) ; Saved copy of $6800 I/O Write byte RAM:0A7F CB 77 bit 6, a RAM:0A81 20 0D jr nz, loc_A90 RAM:0A83 CB F7 set 6, a ; what does Bit #6 in $6800 do in write mode RAM:0A85 CB 9E res 3, (hl) RAM:0A87 RAM:0A87 loc_A87: ; CODE XREF: sub_A56+3E↓j RAM:0A87 32 00 68 ld (loc_67FF+1), a RAM:0A8A 32 F9 85 ld (REG_6800W), a ; Saved copy of $6800 I/O Write byte RAM:0A8D C3 D3 0A jp RESTORE_BNK1 ; Restore Bank#1 from values on the stack RAM:0A90 ; --------------------------------------------------------------------------- RAM:0A90 RAM:0A90 loc_A90: ; CODE XREF: sub_A56+2B↑j RAM:0A90 CB B7 res 6, a RAM:0A92 CB DE set 3, (hl) RAM:0A94 18 F1 jr loc_A87
  19. Hi James, et al. The tokeniser routine at $2509 in the ROM as it processes the input line, uses the first ascii character it finds as an index into a 26 word pointer table, for A-Z: RAM:2509 TOKENIZE: ; CODE XREF: sub_2457+7D↑j RAM:2509 ; sub_2457+93↑j RAM:2509 E1 pop hl ; convert basic keyword to 1 byte TOKEN RAM:250A CD 15 31 call sub_3115 RAM:250D E5 push hl RAM:250E 21 E9 1B ld hl, KEYWD_PTR_ARRAY ; 26 char table, first letter of each RAM:2511 D6 41 sub 41h ; 'A' ; A now ZERO OFFSET into table RAM:2513 87 add a, a RAM:2514 4F ld c, a RAM:2515 06 00 ld b, 0 RAM:2517 09 add hl, bc RAM:2518 5E ld e, (hl) RAM:2519 23 inc hl RAM:251A 56 ld d, (hl) ; DE now points at inividual letter table RAM:251B E1 pop hl RAM:251C 23 inc hl .... RAM:1BE9 1D 1C KEYWD_PTR_ARRAY:dw KEYWORDS_A ; DATA XREF: sub_2457+B7↓o RAM:1BEB 2E 1C dw KEYWORDS_B RAM:1BED 2F 1C dw KEYWORDS_C RAM:1BEF 83 1C dw KEYWORDS_D RAM:1BF1 B0 1C dw KEYWORDS_E RAM:1BF3 D1 1C dw KEYWORDS_F RAM:1BF5 E7 1C dw KEYWORDS_G RAM:1BF7 FB 1C dw KEYWORDS_H RAM:1BF9 00 1D dw KEYWORDS_I RAM:1BFB 1C 1D dw KEYWORDS_J RAM:1BFD 20 1D dw KEYWORDS_K RAM:1BFF 28 1D dw KEYWORDS_L RAM:1C01 5C 1D dw KEYWORDS_M RAM:1C03 81 1D dw KEYWORDS_N RAM:1C05 94 1D dw KEYWORDS_O RAM:1C07 AA 1D dw KEYWORDS_P RAM:1C09 C8 1D dw KEYWORDS_Q RAM:1C0B C9 1D dw KEYWORDS_R RAM:1C0D 0A 1E dw KEYWORDS_S RAM:1C0F 47 1E dw KEYWORDS_T RAM:1C11 62 1E dw KEYWORDS_U RAM:1C13 6B 1E dw KEYWORDS_V RAM:1C15 7B 1E dw KEYWORDS_W RAM:1C17 93 1E dw KEYWORDS_X RAM:1C19 97 1E dw KEYWORDS_Y RAM:1C1B 98 1E dw KEYWORDS_Z RAM:1C1D 55 KEYWORDS_A: db 'U' ; DATA XREF: RAM:KEYWD_PTR_ARRAY↑o RAM:1C1E 54 db 'T' RAM:1C1F CF db 0CFh RAM:1C20 AB db 0ABh ; AUTO $AB RAM:1C21 4E db 'N' RAM:1C22 C4 db 0C4h RAM:1C23 F7 db 0F7h ; AND $F7 RAM:1C24 42 db 'B' RAM:1C25 D3 db 0D3h RAM:1C26 06 db 6 ; ABS $06 RAM:1C27 54 db 'T' RAM:1C28 CE db 0CEh RAM:1C29 0E db 0Eh ; ATN $0E RAM:1C2A 53 db 'S' RAM:1C2B C3 db 0C3h RAM:1C2C 15 db 15h ; ASC $15 RAM:1C2D 00 db 0 RAM:1C2E 00 KEYWORDS_B: db 0 ; DATA XREF: RAM:1BEB↑o RAM:1C2F 4C KEYWORDS_C: db 'L' ; DATA XREF: RAM:1BED↑o RAM:1C30 4F db 'O' .... and so on. Following program will list all the keywords and their corresponding single-byte tokens: 10 A=&H1C1D 20 C=&H40 30 C=C+1 40 B=PEEK(A) 50 IF B=0 THEN A=A+1:GOTO 30 60 PRINT CHR$©; 70 IF B > 127 THEN 110 80 PRINT CHR$(B); 90 A=A+1 100 B=PEEK(A):GOTO 70 110 B=(B AND 127) 120 PRINT CHR$(B), 130 A=A+1 140 B=PEEK(A) 150 PRINT" Token:$";HEX$(B) 160 A=A+1 170 IF A < &H1E96 THEN 40 Still working on discovering all the entry points for the BASIC commands and keywords. Regards, Leslie
  20. Hi Nippur72, Nice work on the double-sided code. Works fine here for me! Looking at the read/write code, I think that whenever the *WRREQ bit (bit 6 in port $10) is turned ON, the controller defaults to writing in self-sync mode. Writing $FF (255) to port $11 turns self-sync *ON*. Writing *any other* value to port $11 turns self-sync *OFF*. I think the 213 ($D5) value is just incidental, as the A register happens to be holding $D5 (next byte written after the self-sync sequence). --- It's interesting to note that the self-sync flag is turned off *after* the $D5 byte is actually written to the data output register. That suggests the self-sync flag is not sampled by the FDC prior to the byte being output, but can be changed mid-byte. I'm presuming the $D5 byte is *not* written as a 10 bit byte? I don't have the real hardware to test unfortunately. (It doesn't actually matter either way if the $D5 ID byte is written as 8 or 10 bits, it will still just magically work ) RAM:66BF D3 10 out (10h), a ; turn on *WRREQ - self-sync *on* by default. RAM:66C1 7A ld a, d ; D = $FF here RAM:66C2 D3 13 out (13h), a RAM:66C4 loc_66C4: RAM:66C4 CD 11 79 call WRITE_DISK_BYTE_D RAM:66C7 10 FB djnz loc_66C4 ; Write $FF 127 times on first loop, sector_gap on rest RAM:66C9 16 D5 ld d, 0D5h RAM:66CB CD 11 79 call WRITE_DISK_BYTE_D RAM:66CE D3 11 out (11h), a ; self-sync *off* RAM:66D0 16 AA ld d, 0AAh RAM:66D2 CD 11 79 call WRITE_DISK_BYTE_D RAM:66D5 16 96 ld d, 96h --- Here is the current state of my disassembly of DOS1.1: http://crisis.com.au/images/LASER_DOS_1.1_DISS.zip Includes the Boot Sector at $A200 Main DOS from $5E00-$7FFF (loaded into bank#6, executed in slot#1) High memory routines copied to $FEE0-$FFAD I've concentrated more on the read/write routines than on the high-level BASIC stuff, but it should be reasonably easy to follow. Regards, Leslie
  21. Hi Nippur72, The GCR encoding employed by the Laser controller requires that all bytes read have the high bit set. No matter where the controller begins reading, after encountering 5 of these $FF self-sync bytes, the next byte read will be guaranteed to be lined up so that the very next byte following the $FF sequence will be correctly aligned , with the read head positioned to read bit 7 of the following byte. DOS never sees the extra two bits, they are just for synchronising the controller with the start of the next data byte. This page in the Beneath Apple Dos book may help to visually explain how the self-sync bytes work: https://archive.org/details/Beneath_Apple_DOS/page/n9 The WRITE_SECTOR routine locates the required sector header. It then switches the write request signal *on* Then writes five self-sync $FF bytes. followed by the D5 AA AD ID bytes before it writes the 342 data bytes, checksum, and DE AA EB trailer bytes. It does not write any self-sync bytes after the data block itself. However, the disk format routine *does* insert self-sync bytes between the DE AA EB trailer bytes, and the following sector header. I'll post a full disassembly in the next few days Regards, Leslie P.S. The track numbers used for the second side of the drive appear to be 40-79, but the track ordering seems reversed. By that I mean track 40 is in the middle of the disk, and track 79 is on the outer edge of the disk: RAM:79B7 ; read/write sector data. B=1 for READ, B=0 for WRITE RAM:79B7 RAM:79B7 READ_WRITE_SEC_DATA: ; CODE XREF: RAM:5F21↑j RAM:79B7 ; sub_644B+36↑p ... RAM:79B7 21 43 FB ld hl, CURRENT_DRIVE RAM:79BA FD 7E 0B ld a, (iy+0Bh) ; examine drive mask RAM:79BD FE 40 cp 40h ; '@' RAM:79BF FD 7E 43 ld a, (iy+43h) ; get current LATCH value RAM:79C2 20 06 jr nz, loc_79CA RAM:79C4 CB AF res 5, a ; drive#1 RAM:79C6 36 01 ld (hl), 1 ; also save in CURRENT_DRIVE RAM:79C8 18 04 jr loc_79CE RAM:79CA ; --------------------------------------------------------------------------- RAM:79CA RAM:79CA loc_79CA: ; CODE XREF: READ_WRITE_SEC_DATA+B↑j RAM:79CA CB EF set 5, a ; drive#2 RAM:79CC 36 02 ld (hl), 2 RAM:79CE RAM:79CE loc_79CE: ; CODE XREF: READ_WRITE_SEC_DATA+11↑j RAM:79CE FD 77 43 ld (iy+43h), a ; save current LATCH value RAM:79D1 FD 7E 12 ld a, (iy+12h) ; Look at Track# RAM:79D4 FD CB 43 BE res 7, (iy+43h) RAM:79D8 FE 28 cp 40 ; Track 40+ denotes second side of the disk? RAM:79DA 38 08 jr c, side_zero RAM:79DC FD CB 43 FE set 7, (iy+43h) ; Set side#2 in the status register RAM:79E0 D6 4F sub 79 ; normalise the Track# RAM:79E2 ED 44 neg ; track numbers on side#2 are reversed? 40 = innermost, 79 = outer. RAM:79E4 RAM:79E4 side_zero: ; CODE XREF: READ_WRITE_SEC_DATA+23↑j RAM:79E4 32 42 FB ld (REQUIRED_TRACK), a RAM:79E7 FD 5E 11 ld e, (iy+11h) ; get sector# R
  22. Hi Nippur, Thanks for the welcome There isn't any need to emulate the "8/16" latch on your emulator. The byte values will always be correctly synchronised when working with disk images. The "self-sync" bytes are important on a *real* disk drive to allow the disk controller to get itself in sequence with the start of each byte. Example Disk stream: Sector header, 5 $FF self-sync bytes, Sector data, trailer, more $FF self-sync bytes.... next Sector Header. D5 AA 96 <VOL> <TRK> <SEC> <CHK> DE AA EB FF FF FF FF FF D5 AA AD <342 bytes of 6+2 encoded data> <CHK> DE AA EB FF FF FF FF .... The $FF self-sync bytes are actually 10 bits long, with two trailing ZEROS: 11111111001111111100111111110011111111001111111100 then <D5> 11010101 ..... The sector data area can be re-written. That means the area between DE AA EB and D5 AA AD can be overwritten multiple times, causing that area to be inconsistent. The 5 x $FF self-sync bytes *guarantee* that by the time the controller reaches the "D5" byte in the D5 AA AD sector data area, it will be correctly synced up bytewise. Doesn't matter where the controller starts reading in the byte stream, after 5 $FF self-sync bytes, it will be correct. Code from the 1.1 Format Disk routine that turns self-sync mode on and off: RAM:6701 16 EB ld d, 0EBh RAM:6703 CD 11 79 call WRITE_DISK_BYTE_D RAM:6706 06 04 ld b, 4 RAM:6708 16 FF ld d, 0FFh RAM:670A CD 11 79 call WRITE_DISK_BYTE_D RAM:670D D3 11 out (11h), a ; self-sync *on* RAM:670F RAM:670F loc_670F: ; CODE XREF: FORMAT_DISK+83↓j RAM:670F CD 11 79 call WRITE_DISK_BYTE_D RAM:6712 10 FB djnz loc_670F RAM:6714 16 D5 ld d, 0D5h RAM:6716 CD 11 79 call WRITE_DISK_BYTE_D RAM:6719 D3 11 out (11h), a ; self-sync *off* RAM:671B 16 AA ld d, 0AAh RAM:671D CD 11 79 call WRITE_DISK_BYTE_D RAM:6720 16 AD ld d, 0ADh --------------- For double sided formatting: Select the drive you want to use with "DRIVE 1" or "DRIVE 2". Then try "INIT:D" It may give some odd results on your emulator, as there isn't any code to handle the side-select bit yet? Regards, Leslie
  23. Just looking at the differences between DOS1.0 and DOS1.1. One thing that immediately stands out is that DOS 1.1 supports formatting double sided floppys. Init command followed by a 'D' will format a disk as double sided if a double sided drive is attached. Cheers, Leslie DOS 1.1 INIT code: RAM:661E INIT: ; CODE XREF: RAM:5F12↑j RAM:661E ; DATA XREF: RAM:63CA↑o RAM:661E CD ED 69 call GET_DRIVESPEC RAM:6621 CD F4 69 call CHECK_DOUBLE_SIDED RAM:6624 E5 push hl RAM:6625 FD CB 43 BE res 7, (iy+43h) ; Select Side #0 RAM:6629 CD 8F 66 call FORMAT_DISK ; format side #0 RAM:662C B7 or a RAM:662D C2 06 62 jp nz, dos_error RAM:6630 3A 40 FB ld a, (DOUBLE_SIDED) RAM:6633 B7 or a RAM:6634 28 0B jr z, loc_6641 RAM:6636 FD CB 43 FE set 7, (iy+43h) ; select side #1 RAM:663A CD 8F 66 call FORMAT_DISK ; format side #1 RAM:663D B7 or a RAM:663E C2 06 62 jp nz, dos_error ... RAM:69F4 CHECK_DOUBLE_SIDED: ; CODE XREF: RAM:6621↑p RAM:69F4 ; RAM:loc_6C62↓p RAM:69F4 E5 push hl RAM:69F5 CD E2 69 call sub_69E2 RAM:69F8 FE 44 cp 44h ; 'D' ; 'D' on command line to specify double sided RAM:69FA 20 0C jr nz, single_sided RAM:69FC CD E2 69 call sub_69E2 RAM:69FF 20 07 jr nz, single_sided RAM:6A01 3E AA ld a, 0AAh RAM:6A03 32 40 FB ld (DOUBLE_SIDED), a RAM:6A06 F1 pop af RAM:6A07 C9 ret RAM:6A08 ; --------------------------------------------------------------------------- RAM:6A08 RAM:6A08 single_sided: ; CODE XREF: CHECK_DOUBLE_SIDED+6↑j RAM:6A08 ; CHECK_DOUBLE_SIDED+B↑j RAM:6A08 E1 pop hl RAM:6A09 AF xor a RAM:6A0A 32 40 FB ld (DOUBLE_SIDED), a RAM:6A0D C9 ret
  24. Hi Bonstra, Nippur72, et al. Going through the disk formatting code(see below) in DOS 1.0, the "8/16" register appears to enable/disable "self-syncing" bytes. I don't think "16" is correct, but rather 10 bit bytes are written to the disk output stream. 8 data bits of $FF plus two extra zero bits. After reading 5 of these "self-sync" bytes, the controller is guaranteed to be "locked on" to the incoming bytes. (See the beneath apple dos book for more info). Self-sync bytes appear to be *disabled* when write mode is turned on. Writing a $FF to port $11 turns 10 bit self-sync mode *ON*. Writing anything but $FF to port $11 turns the self-sync mode *OFF*, and returns to writing 8 bit bytes. Regards, Leslie RAM:6634 FORMAT_DISK: ; CODE XREF: RAM:65DF↑p RAM:6634 CD E0 7B call SELECT_DRIVE ; format 40 track disk. Zero all sectors RAM:6637 3E 11 ld a, 11h RAM:6639 FD 77 14 ld (iy+14h), a RAM:663C AF xor a RAM:663D FD 77 11 ld (iy+11h), a RAM:6640 FD 77 7F ld (iy+7Fh), a ; start at Track/Sector 0/0 RAM:6643 FD 77 7E ld (iy+7Eh), a RAM:6646 FD 7E 7D ld a, (iy+7Dh) RAM:6649 FD 77 7C ld (iy+7Ch), a ; Volume # RAM:664C 06 28 ld b, 40 RAM:664E CD CA 78 call STEP_HEAD_OUT RAM:6651 3E 0E ld a, 14 ; Set initial gap between sectors at 14 bytes of $FF RAM:6653 32 5B FE ld (SECTOR_GAP), a RAM:6656 RAM:6656 format_track: ; RAM:6656 06 7F ld b, 127 RAM:6658 0E 10 ld c, 16 ; 16 sectors per track RAM:665A 16 FF ld d, 0FFh RAM:665C FD 7E 43 ld a, (iy+43h) RAM:665F E6 BF and 0BFh ; 10111111 - turn on *WRREQ bit 6 RAM:6661 FD 77 43 ld (iy+43h), a ; Save copy of LATCH register RAM:6664 D3 10 out (10h), a ; turn on *WRREQ RAM:6666 7A ld a, d ; D = $FF here RAM:6667 D3 13 out (13h), a RAM:6669 RAM:6669 loc_6669: ; PC_START+670B↓j RAM:6669 CD 64 78 call WRITE_DISK_BYTE_D ; byte written is returned in A RAM:666C 10 FB djnz loc_6669 ; Write $FF 127 times RAM:666E 16 D5 ld d, 0D5h RAM:6670 CD 64 78 call WRITE_DISK_BYTE_D ; byte written is returned in A RAM:6673 D3 11 out (11h), a ; turn off self-sync RAM:6675 16 AA ld d, 0AAh RAM:6677 CD 64 78 call WRITE_DISK_BYTE_D ; byte written is returned in A RAM:667A 16 96 ld d, 96h RAM:667C CD 64 78 call WRITE_DISK_BYTE_D ; byte written is returned in A RAM:667F FD 56 7C ld d, (iy+7Ch) RAM:6682 42 ld b, d ; 1st byte is VOLUME # RAM:6683 CD 6D 78 call WRITE_4X4_D ; write 4x4 track/sector header ID bytes RAM:6686 FD 7E 7F ld a, (iy+7Fh) RAM:6689 57 ld d, a ; Second Byte is TRACK # RAM:668A A8 xor b .......
×
×
  • Create New...