reifsnyderb Posted March 31 Author Share Posted March 31 (edited) 7 minutes ago, kheller2 said: I didn't realize they were that unclean. I see the page header command in there but it looks like all the returns and line feeds have been removed. I few quick Unix scripts could clean them up. Is there something you want me to look at first? Not your fault. I am really glad you posted the files as there are some good clues as to how this was supposed to work. I just didn't spend much time trying to figure it all out. I don't know what should be cleaned up first. If a few Unix scripts could clean them up that would be great! Edited March 31 by reifsnyderb Quote Link to comment Share on other sites More sharing options...
invisible kid Posted March 31 Share Posted March 31 (edited) I took a quick look at cleaning them up. It looks like cr/lf's were replaced globally with tabs. So now, some tabs are supposed to be tabs, and some tabs are supposed to be line feeds. I hope I am wrong because it would be difficult/impossible for a script or command to be able to tell the difference and clean them up. Or maybe like someone else said, all cr/lfs were just stripped out, which would be equally hard to replace by script or command. Edited March 31 by invisible kid Quote Link to comment Share on other sites More sharing options...
ivop Posted March 31 Share Posted March 31 (edited) 27 minutes ago, invisible kid said: I took a quick look at cleaning them up. It looks like cr/lf's were replaced globally with tabs. So now, some tabs are supposed to be tabs, and some tabs are supposed to be line feeds. I hope I am wrong because it would be difficult/impossible for a script or command to be able to tell the difference and clean them up. Or maybe like someone else said, all cr/lfs were just stripped out, which would be equally hard to replace by script or command. Yeah, looks like all CR/LFs are missing. Replacing tab by newline+tab makes it sort of readable (sed 's/\t/\n\t/g') but not all. Some files have single CRs at some lines. But with some manual intervention it could be turned into proper source code. Except for the binary blobs (BIOS, BDOS, CCP) which are .byte statement hexdumps of 8080/Z80 code. IMHO it would be easier to write your own BIOS and the Atari side of things. If you know how CP/M works, it's one to two days work to get that working, provided that the card allows the Z80 to be halted after a request is made and the 6502 can access the RAM memory again. Edited March 31 by ivop 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted March 31 Author Share Posted March 31 49 minutes ago, ivop said: IMHO it would be easier to write your own BIOS and the Atari side of things. If you know how CP/M works, it's one to two days work to get that working, provided that the card allows the Z80 to be halted after a request is made and the 6502 can access the RAM memory again. That sounds like what will have to be done. I am working on a new card that uses a lot of PLDs and has it's own SRAM on board. It will be controlled by $D1F0 in a manner similar to the schematic, have the capability to bank the memory, have it's own clock for the Z-80, permit DMA by the 6502, and use about 10 chips. 2 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) 2 hours ago, reifsnyderb said: That sounds like what will have to be done. I am working on a new card that uses a lot of PLDs and has it's own SRAM on board. It will be controlled by $D1F0 in a manner similar to the schematic, have the capability to bank the memory, have it's own clock for the Z-80, permit DMA by the 6502, and use about 10 chips. That sounds good! Basically it comes down to this: 6502 sets up the Z80 memory map: $0000-$0007 (W)BOOT vector and BDOS vectors ($e400 CCP optional, should reload on (W)BOOT anyway) $ec00 BDOS $fa00 BIOS (2kB should be more than enough) BIOS needs entry points for each call, and a disk parameter block (also called DPH). For BDOS to find BIOS, you have to hardcode all addresses in bdos.asm The disk parameter block is what SELDSK returns in HL. BDOS calls that to know where it is and to know how the disk is formatted. start Z80 (which starts running at $0000, which points to BOOT, changed to WBOOT after that during BOOT, WBOOT always reloads CCP.SYS) each BIOS call does: save parameter A, BC, and HL to a fixed location (say $ff00, ignore DE as we don't do sector translation (sector skew)) signal 6502 we want BIOS call number x busy wait for ACK reload A, BC and HL from memory RET 6502 does: wait for BIOS request stop Z80 dispatch on request number X read Z80's C or BC (depends on call) from memory execute bios call (CONIN, CONOUT, READ/WRITE sector directly in to/out of Z80 memory, etc...) set return values in Z80 memory (A, C, HL, whatever applies) start Z80 signal ACK Short description of BIOS calls: https://www.seasip.info/Cpm/bios.html You can ignore LIST, PUNCH, READER, SECTRAN and LISTST. You could save a copy of CCP outside of the Z80 memory so you can reload it very fast when WBOOT is called. You can start with the Atari E: device as CONOUT, switch to a proper dumb terminal later (so Atari special characters are printed as characters instead), and after that something like ADM-3a or VT-52 in 40 and/or 80 columns. For inspiration you could look at the CP/M-65 terminal implementations. As dmsc would say, have fun! Edited April 1 by ivop 3 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 1 hour ago, ivop said: That sounds good! Basically it comes down to this: 6502 sets up the Z80 memory map: $0000-$0007 (W)BOOT vector and BDOS vectors ($e400 CCP optional, should reload on (W)BOOT anyway) $ec00 BDOS $fa00 BIOS (2kB should be more than enough) BIOS needs entry points for each call, and a disk parameter block (also called DPH). For BDOS to find BIOS, you have to hardcode all addresses in bdos.asm The disk parameter block is what SELDSK returns in HL. BDOS calls that to know where it is and to know how the disk is formatted. start Z80 (which starts running at $0000, which points to BOOT, changed to WBOOT after that during BOOT, WBOOT always reloads CCP.SYS) each BIOS call does: save parameter A, BC, and HL to a fixed location (say $ff00, ignore DE as we don't do sector translation (sector skew)) signal 6502 we want BIOS call number x busy wait for ACK reload A, BC and HL from memory RET 6502 does: wait for BIOS request stop Z80 dispatch on request number X read Z80's C or BC (depends on call) from memory execute bios call (CONIN, CONOUT, READ/WRITE sector directly in to/out of Z80 memory, etc...) set return values in Z80 memory (A, C, HL, whatever applies) start Z80 signal ACK Short description of BIOS calls: https://www.seasip.info/Cpm/bios.html You can ignore LIST, PUNCH, READER, SECTRAN and LISTST. You could save a copy of CCP outside of the Z80 memory so you can reload it very fast when WBOOT is called. You can start with the Atari E: device as CONOUT, switch to a proper dumb terminal later (so Atari special characters are printed as characters instead), and after that something like ADM-3a or VT-52 in 40 and/or 80 columns. For inspiration you could look at the CP/M-65 terminal implementations. As dmsc would say, have fun! It sounds like you are ready to implement this! I've found this, which has a skeletal BIOS and I think there is some BIOS code in the files that were posted: http://www.cpm.z80.de/manuals/cpm22-m.pdf Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) 12 hours ago, reifsnyderb said: It sounds like you are ready to implement this! I could probably do that, if I had the hardware Thinking about it some more, the communication between the 6502 and the Z80 needs to be a little more robust to avoid running into a race condition or executing the same BIOS command twice. Perhaps more like: Z80: check if 6502 is ready for command 6502: signal ready for command Z80: send command 6502: recv command Z80: wait for done 6502: halt Z80, do command, signal done, start Z80 Z80: wait for done, recv done, signal ack 6502: wait for ack, recv ack, loop to signal ready for command Z80: continue 12 hours ago, reifsnyderb said: I've found this, which has a skeletal BIOS and I think there is some BIOS code in the files that were posted: http://www.cpm.z80.de/manuals/cpm22-m.pdf http://github.com/ivop/atari8080 contains a 8080 emulator I wrote in C and in 6502 assembly. In the C version I did a full BIOS implementation (around 160 lines of C code). The 130XE 6502 version contains just enough BIOS to output the test suite results via CONOUT. I was working on porting it to CP/M-65 to run on top of its BIOS, i.e. translating the 8080 BIOS calls to CP/M-65 BIOS calls. That's mostly finished, but then I got sidetracked by another project It still needs the CP/M-65 overlay loader and read/write sector translation. Then you basically have 95% of the code you need to get your card running if you were to run it on top of CP/M-65. If you look in the cpm22 directory of the aforementioned repo, you'll find a much simpler BIOS skeleton (bios.asm) and the adapted bdos.asm with the needed hardcoded BIOS addresses. If you wanted to to stay closer to what Atari did, you could try extracting the hexdumps from the .MAC files (CPMBIOS, CPMBDOS and CPMCCP, highest .number extension) and run them through a disassembler. BDOS and CCP are unmodified from Digital's sources, except for the hardcoded BIOS entries. Perhaps you can deduct from CPMBOOT where in the Z80 memory they are loaded. Looking at the hexdumps, BDOS does some calls with 0CDH (=CALL) 006H 04AH, or 009H 04AH, etc. (low byte increasing by 3 for each next BIOS call) and the BIOS starts with jumps for each BIOS call (0C3H (=JMP) and then an address in the $4Axx range, total of three bytes per entry). BDOS starts at offset +6 (after the six byte "serial") with JMP BDOSE which is 0C3H and the address 03C11H. BDOS at $3c00 and BIOS at $4a00. Pretty weird numbers if the Z80 had 64kB of RAM. CCP starts with JMP CCPSTART (which is three pages in), .Byte 0C3,05C,037, so CCP should start at $3400. So instead of pages $e4, $ec and $fa (which I had expected and pretty standard across 64kB CP/Ms) they appear to start at pages $34, $3c and $4a. Perhaps they were debug builds? They should be at the end of the TPA (Transient Program Area, read free memory), not somewhere in the middle. TPA from 00100H to 03BFFH (CCP is allowed to be overwritten if the program ends with WBOOT instead of RET) is pretty small and cannot run Zork for example. Edited April 1 by ivop 2 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 I need to study this schematic a little more to double-check everything, but I think it will work.... CPM.pdf Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 7 minutes ago, ivop said: I could probably do that, if I had the hardware Thinking about it some more, the communication between the 6502 and the Z80 needs to be a little more robust to avoid running into a race condition or executing the same BIOS command twice. Perhaps more like: Z80: check if 6502 is ready for command 6502: signal ready for command Z80: send command 6502: recv command Z80: wait for done 6502: halt Z80, do command, signal done, start Z80 Z80: wait for done, recv done, signal ack 6502: wait for ack, recv ack, loop to signal ready for command Z80: continue http://github.com/ivop/atari8080 contains a 8080 emulator I wrote in C and in 6502 assembly. In the C version I did a full BIOS implementation (around 160 lines of C code). The 130XE 6502 version contains just enough BIOS to output the test suite results via CONOUT. I was working on porting it to CP/M-65 to run on top of its BIOS, i.e. translating the 8080 BIOS calls to CP/M-65 BIOS calls. That's mostly finished, but then I got sidetracked by another project It still needs the CP/M-65 overlay loader and read/write sector translation. Then you basically have 95% of the code you need to get your card running if you were to run it on top of CP/M-65. If you look in the cpm22 directory of the aforementioned repo, you'll find a much simpler BIOS skeleton (bios.asm) and the adapted bdos.asm with the needed hardcoded BIOS addresses. If you wanted to to stay closer to what Atari did, you could try extracting the hexdumps from the .MAC files (CPMBIOS, CPMBDOS and CPMCCP) and run them through a disassembler. BDOS and CCP are unmodified from Digital's sources, except for the hardcoded BIOS entries. Perhaps you can deduct from CPMBOOT where in the Z80 memory they are loaded. Looking at the hexdumps, BDOS does some calls with 0CDH (=CALL) 006H 04AH, or 009H 04AH, etc. (low byte increasing by 3 for each next BIOS call) and the BIOS starts with jumps for each BIOS call (0C3H (=JMP) and then an address in the $4Axx range, total of three bytes per entry). BDOS starts at offset +6 (after the six byte "serial") with JMP BDOSE which is 0C3H and the address 03C11H. BDOS at $3c00 and BIOS at $4a00. Pretty weird numbers if the Z80 had 64kB of RAM. CCP starts with JMP CCPSTART (which is three pages in), .Byte 0C3,05C,037, so CCP should start at $3400. So instead of pages $e4, $ec and $fa (which I had expected and pretty standard across 64kB CP/Ms) they appear to start at pages $34, $3c and $4a. Perhaps they were debug builds? They should be at the end of the TPA (Transient Program Area, read free memory), not somewhere in the middle. TPA from 00100H to 03BFFH (CCP is allowed to be overwritten if the program ends with WBOOT instead of RET) is pretty small and cannot run Zork for example. It sounds like it would be just as "easy" to re-implement the BIOS. What is the absolute minimum number of devices I need to get working? Keyboard input, screen output, disk access? I was reading that C compilers don't output the greatest Z-80 code. I have almost zero Z-80 experience, so I really don't know. Is this true? I also found out that Wozmon has been ported to the Z-80. I am wondering if it would be worthwhile to implement here or if it would just be a distraction.... How long do you think it would take to get this working if you had the hardware? Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 2 minutes ago, reifsnyderb said: It sounds like it would be just as "easy" to re-implement the BIOS. What is the absolute minimum number of devices I need to get working? Keyboard input, screen output, disk access? Yes, that's all. You need: BOOT ; read BDOS into memory, or NOP if that's part of the init procedure the 6502 does WBOOT ; read CCP into memory CONST ; Console status, key available yes/no CONIN ; Console input, read key from Atari K: CONOUT ; Console output, write character to E: SELDSK ; Select disc drive, fixed to drive 0 (=A) (multiple drives could be added later) SETTRK ; Set track number, store somewhere SETSEC ; Set sector number, store somewhere SETDMA ; Set DMA address, store somewhere READ ; Read a sector, calculate Atari sector number with TRK and SEC, read WRITE ; Write a sector, idem, write You can ignore: HOME ; Move disc head to track 0 LIST ; Printer output PUNCH ; Paper tape punch output READER ; Paper tape reader input LISTST ; Status of list device SECTRAN ; Sector translation for skewing I just found this in an old CP/M document: MEMORY ALLOCATION ================= V1.4: b = memsize-16K 0000 - 00FF System scratch area 0100 - 28FF+b TPA (Transient Program Area) - COM file area 2900+b - 30FF+b CCP - Console Command Processor 3100+b - 3DFF+b BDOS 3E00+b - 3FFF+b BIOS V2.2: b = memsize-20K 0000 - 00FF System scratch area 0100 - 33FF+b TPA (Transient Program Area) - COM file area 3400+b - 3BFF+b CCP - Console Command Processor 3C00+b - 49FF+b BDOS 4A00+b - 4FFF+b BIOS That's where the 3400 came from. The Atari builds were not adjusted for 64kB memory yet. 2 minutes ago, reifsnyderb said: I was reading that C compilers don't output the greatest Z-80 code. I have almost zero Z-80 experience, so I really don't know. Is this true? Yes, that's true. I was not suggesting writing it in C. The C code I referenced was just meant as an example of how small and simple a BIOS implementation can be. 2 minutes ago, reifsnyderb said: I also found out that Wozmon has been ported to the Z-80. I am wondering if it would be worthwhile to implement here or if it would just be a distraction.... I think as long as you don't have a way to interact with it (keyboard, screen) it has little value And once you have CP/M running, there's http://www.cpm.z80.de/randyfiles/DRI/DDT.pdf 2 minutes ago, reifsnyderb said: How long do you think it would take to get this working if you had the hardware? Probably a week or so. But considering I am sometimes unable to do stuff for weeks because of an illness, and other times I barely manage 1-2 hours a day, I'm not sure if I am the right person to take on yet another project. But I can help you or somebody else through this forum. 1 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 Schematic with PLD pseudo-code added.... CPM.pdf 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 @ivop Thanks for the information! I can do this, but with zero Z-80 and CP/M experience, I figure it will take me quite some time. I am concerned about an issue whereby I need to have disk access without having a clue as to the format of the disk nor having a compatible disk. The disk has to, obviously, be compatible with an Atari disk. So, I figure a single density 90k disk should be a starting point. Presently, I don't have an idea as to what the format would look like. Is there some sort of disk format information for CP/M I can refer to? I figure it would be possible to format a disk and just re-arrange the structures into a CP/M format. Then, with CP/M running, it will at least have something to look at. Thanks! Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) You can create CP/M disks with cpmtools on Linux or WSL2 on Windows. We use it to create the disk images for CP/M-65. It reads a diskdefs file and you supply the format with the -f command line option, like this: mkfs.cpm -f atari90 disk.img /usr/bin/printf '\x96\x02\x80\x16\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > disk.atr cat disk.img >> disk.atr Or a 1MB image for use with drive emulators or mount with SIDE: mkfs.cpm -f atarihd disk.img /usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > disk.atr cat disk.img >> disk.atr Different ATR header for the big image. I hardcoded /usr/bin/printf because the bash builtin printf is broken. In between the mkfs and printf you can copy files to the image with cpmcp, list its directory with cpmls, etc.. cpmfs -f atari90 disk.img foo.txt 0:FOO.TXT cpmls -f atari90 disk.img Edit: The prepended 0: means user area 0 (the default). CP/M uses user areas to separate files. Sort of a poor man's directory, but there's no PATH and no copy between them. Most of the CP/M users pretend they don't exist and put everything in 0:. For the Atari images, I put the platform specific files in user area 1 though. Edited April 1 by ivop 4 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 4 minutes ago, ivop said: You can create CP/M disks with cpmtools on Linux or WSL2 on Windows. We use it to create the disk images for CP/M-65. It reads a diskdefs file and you supply the format with the -f command line option, like this: mkfs.cpm -f atari90 disk.img /usr/bin/printf '\x96\x02\x80\x16\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > disk.atr cat disk.img >> disk.atr Or a 1MB image for use with drive emulators or mount with SIDE: mkfs.cpm -f atarihd disk.img /usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > disk.atr cat disk.img >> disk.atr Different ATR header for the big image. I hardcoded /usr/bin/printf because the bash builtin printf is broken. In between the mkfs and printf you can copy files to the image with cpmcp, list its directory with cpmls, etc.. cpmfs -f atari90 disk.img foo.txt 0:FOO.TXT cpmls -f atari90 disk.img I was under the impression that a disk formatted in a PC compatible floppy drive was not accessible by a 1050. Am I wrong? Do I need an ATR8000 and PC compatible floppy disks? Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) 17 minutes ago, reifsnyderb said: I was under the impression that a disk formatted in a PC compatible floppy drive was not accessible by a 1050. Am I wrong? Do I need an ATR8000 and PC compatible floppy disks? mkfs.cpm just creates a disk file that contains the CP/M filesystem. I just noticed (and forgot to mention) that it does not expand the file to 720*128 bytes, so it's best to first create an empty disk.img file of 720*128 bytes and then write the CP/M filesystem to it. Once converted to ATR you can use it with your favorite emulator (atari800, Altirra, atari++) or disk emulator like SDrive or RespeQt. If you want a real floppy, you can just sector copy it from there to a real drive. PC compatible drives do indeed not work correctly. Edit: before the mkfs.cpm -f atari90 disk.img, you can do: dd if=/dev/zero of=disk.img bs=128 count=720 to create the empty file. If later you have files written to the ATR encapsulated image with CP/M running on the Atari, you can convert it back to a plain image with: dd if=disk.atr of=disk.img bs=1 skip=16 And then copy files out of it with cpmcp. Edited April 1 by ivop 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 3 minutes ago, ivop said: mkfs.cpm just creates a disk file that contains the CP/M filesystem. I just noticed (and forgot to mention) that it does not expand the file to 720*128 bytes, so it's best to first create an empty disk.img file of 720*128 bytes and then write the CP/M filesystem to it. Once converted to ATR you can use it with your favorite emulator (atari800, Altirra, atari++) or disk emulator like SDrive or RespeQt. If you want a real floppy, you can just sector copy it from there to a real drive. PC compatible drives do indeed not work correctly. Ok. I'll be working with a real floppy. A couple months ago, I stumbled across 3 boxes of floppy disks in my basement. All unopened! They are labelled as being DS/DD and have the hub ring. I think they'll work. 🙂 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) Just for fun, I partly disassembled the Z80 BIOS bios-disasm.zip I decoded the Disk Parameter Headers, but did not decode the Disk Parameter Block (shared by all four drives). CSV means checksum vector, and ALV means allocation vector. It looks like it communicates with the Atari a lot simpler than I expected. It uses memory at $fbf0-$fbfa for the message it wants to send, and just toggles out ($00),a to $ff, waits until the Atari has set $fbf0 to $ff, and then toggles out ($00),a back to zero, copies a byte from $fbf1 to $4daf, reads status from $fbf9, compares with 1 and returns or prints an error (code after ret z) when it's not 1: sub_4c70h: ld a,0ffh ;4c70 3e ff > . out (000h),a ;4c72 d3 00 . . l4c74h: ld a,(0fbf0h) ;4c74 3a f0 fb : . . cp 0ffh ;4c77 fe ff . . jr nz,l4c74h ;4c79 20 f9 . ld a,000h ;4c7b 3e 00 > . out (000h),a ;4c7d d3 00 . . ld a,(0fbf1h) ;4c7f 3a f1 fb : . . ld (04dfah),a ;4c82 32 fa 4d 2 . M ld a,(0fbf9h) ;4c85 3a f9 fb : . . cp 001h ;4c88 fe 01 . . ret z ;4c8a c8 . $fc00 and beyond seems to be used to exchange data. A read key is loaded from there: ; end of CONIN ld a,(0fc00h) ;4b3c 3a 00 fc : . . and 07fh ;4b3f e6 7f . ^? ; mask out upper bits, 7-bit ASCII ret ;4b41 c9 . And even reading a sector is put there: ld a,(0fbf2h) ;4c24 3a f2 fb : . . cp 052h ;4c27 fe 52 . R jr nz,l4c37h ;4c29 20 0c . ld hl,(DMA_STORAGE) ;4c2b 2a 04 4d * . M ld de,0fc00h ;4c2e 11 00 fc . . . ex de,hl ;4c31 eb . ld bc,00080h ;4c32 01 80 00 . . . ldir ;4c35 ed b0 . . l4c37h: ld a,000h ;4c37 3e 00 > . ret ;4c39 c9 . Compare $fbf2 with 'R', if not equal, load A with return status 0 and RET (we did a write, read and write share a lot of code). If equal, use LDIR (LDI repeat) to copy 128 (080h) bytes from $fc00 to where DMA_STORAGE points to (set with SET_DMA BIOS call). I think I'll stop here. I hate z80dasm and couldn't find a GUI disassembler. Note that having the command and data at $fbf0-$fc7f would conflict when the BIOS would be moved to upper memory, starting at $fa00, but it looks like Atari didn't get that far yet. The BIOS code stops at $4cff, so they would probably moved that space to $fef0-$ff7f or something. Anyway, the idea of simply toggling to $ff and back to $00 with out (0),a could be reused, and have all other communications done through shared RAM. That would simplify things a lot. Edit: it would be faster if "our" code just read a sector directly to where DMA_STORAGE points instead of the extra copy that's done here. Edited April 1 by ivop 1 2 Quote Link to comment Share on other sites More sharing options...
+kheller2 Posted April 1 Share Posted April 1 Yeah cleaning up these files is ugly! CRs were completely nuked. You can kind of make things out by replace \t\t with \r\t\t but that makes messes of tables. I have no idea if this table I tried to restore is correct. DEVICE CODES 00-13 HEX - STANDARD I/O CPM ATASCII/ASCII ATARI OS IMMEDIATE MASKED DEVICE CODE CONVERSION IOCB DEVICE RETURN NOTES IOBYTE 00 TTY: 0 YES - K: NO FOR INPUT 00 TTY: 8 YES - E: YES FOR OUTPUT 01 CRT: 1 YES (0) K: NO FOR INPUT 01 CRT: D YES - S: YES FOR OUTPUT 02 BAT: - - - - - NOT SUPPORTED 03 UC1: 3 YES (0) K: NO FOR INPUT 03 UC1: 9 YES (8) E: YES FOR OUTPUT 00 TTY: 4 YES (0) K: NO INPUTS 04 RDR: 5 NO - R1: NO 08 UR1: 6 NO - M: NO 0C UR2: 7 NO - R2: NO 00 TTY: 8 YES - E: YES OUTPUTS 10 PUN: 9 NO (5) R1: YES 20 UP1: A NO (6) M: YES 30 UP2: B NO (7) R2: YES 00 TTY: C YES (8) E: YES OUTPUTS 40 CRT: D YES - S: YES 80 LPT: E YES - P: YES C0 UL1: F NO (5) R1: YES (x) SEE IOCB OF CPM CODE x Most of these assignments are table driven and can be reassigned by ATSTAT.COM. TTY: is reserved to ATARI and is not user changeable. DEVICE CODES 80-8F HEX - DISK TYPE DEVICES CPM ATARI OS DEVICE CODE DEVICE A: 80 D1: B: 81 D2: C: 82 D3: D: 83 D4: E: 84 RESERVED FOR FUTURE DOUBLE DENSITY FLOPPY DISK F: 85 " " " " " " " G: 86 " " " " " " " H: 87 " " " " " " " I: 88 RESERVED FOR FUTURE HARD DISK J: 89 " " " " " K: 8A " " " " " 3 2 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 @kheller2 That looks a lot cleaner than my clean-up attempt. I was also looking at it from the view of somebody who knows almost nothing about CP/M. 🙂 @ivop Please continue! Any more insights as to how this thing should work is very helpful. With enough pieces, this puzzle can come back together. 🙂 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 (edited) Here's some more. I made educated guesses whether constants were hex (e.g. 9BH, /100H, etc..) or decimal. Note that the original dumps said /100 when they mean /256 decimal (high byte), hence 100H. Some interesting things. The 64K stuff seems untested, as cold boot points to $FA00 (as expected, start of BIOS, runs BOOT), but the data transfer area is at $FC00, which would overwrite the BIOS. The Atari OS loads 54 sectors of boot code, which is exactly 3*18 sectors, i.e. three tracks. The old Atari CP/M-65 used the same format until the BDOS loader was added and the boot code was reduced to 1 track. CP/M directory starts at sector 55, which corresponds to 3 reserved tracks (see diskdefs for reserved tracks, currently 1 for the atari90 and atarihd formats, change to 3 to match the 1984 Atari format) The Atari boot code uses self modifying code to copy the Z80 code to the memory banks. Their assembler supported inline labels for that (LDA @FROM(X), which would translate to lda from: $1234,x in mads syntax) The equates look like a mix between 20K and 64K equates (e.g. the location of the data transfer area and the command frame). Hardware and Z80 board addresses from 6502 viewpoint! Command frame in mem bank 3 07BF0H translates to 0FBF0H which corresponds to the 20K Z80 BIOS disassembly. Bank numbers are numbered backwards (BANK0=3, BANK3=0) cpmboot.asm cpmequates.inc Edited April 1 by ivop 3 2 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 1 hour ago, kheller2 said: Yeah cleaning up these files is ugly! CRs were completely nuked. You can kind of make things out by replace \t\t with \r\t\t but that makes messes of tables. I have no idea if this table I tried to restore is correct. Looks good. CP/M supported remapping of devices with the STAT.COM command. Atari had their custom ATSTAT.COM version which would update the BIOS tables. You can see the tables in my disassembly in the data3 block, starting at 4b96h are different mappings for CON, LIST, and READER. I think if a complete rewrite of a much simpler BIOS is done, remapping could be skipped. CP/M-65 doesn't support it either. It's pretty pointless nowadays. 1 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted April 1 Author Share Posted April 1 11 minutes ago, ivop said: Looks good. CP/M supported remapping of devices with the STAT.COM command. Atari had their custom ATSTAT.COM version which would update the BIOS tables. You can see the tables in my disassembly in the data3 block, starting at 4b96h are different mappings for CON, LIST, and READER. I think if a complete rewrite of a much simpler BIOS is done, remapping could be skipped. CP/M-65 doesn't support it either. It's pretty pointless nowadays. Simple will be good! It will be easier to implement. I found the following page, which describes CP/M's extremely simple file system... https://obsolescence.wixsite.com/obsolescence/cpm-internals The more info we have, the better. 🙂 1 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 1 Share Posted April 1 2 hours ago, reifsnyderb said: Simple will be good! It will be easier to implement. I found the following page, which describes CP/M's extremely simple file system... https://obsolescence.wixsite.com/obsolescence/cpm-internals The more info we have, the better. 🙂 That's a nice overview what CP/M is. Note that the addresses of CCP, BDOS and BIOS are yet again different. It al depends on the platform, and there were a ton of them in the 70's and early 80's. And a lot of them had their own custom disk format. The diskdefs supplied with cpmtools has: $ grep ^diskdef /etc/cpmtools/diskdefs | wc -l 98 But there were more. Nevertheless, they were all binary compatible (Intel 8080) which was the main selling point at the time, except for memory requirements for some programs. That changed once systems with Z80's were shipped. The core (BDOS and CCP) were still i8080, but the BIOS and a lot of newer programs were Z80 only (MS Basic, Turbo Pascal, Wordstar). Starting from around 1980 it was more or less a requirement to have a Z80 system to run proper productivity applications. Luckily, except for the BIOS call addresses in BDOS, you can treat BDOS and CCP as binary blobs and just run them. BDOS abstracts the drive based on the Disk Parameter Block in the BIOS, and CCP is the silly command line processor (silly, because rename is REN NEWFILE=OLDFILE, and copy with PIP DEST=SRC, and more). 1 Quote Link to comment Share on other sites More sharing options...
sup8pdct Posted April 2 Share Posted April 2 Here is some notes that i found. NOTES: 1. FRAME is set to 0FF to indicate completion of service request. 2. All IOCB's are allocated as required. 3. IOCB OFFSETs are 00-IOCB0 .... 70-IOCB7, if the IOCB OFFSET is specified as 0FF, then the next free IOCB will be assigned, and the assigned offset will be returned in FCOMD. 4. Return STATUS is 01 to indicate success, any other code indicates some form of error (negative) or warning (positive). 5. The X and Y registers and the accumulator are set to the call values before an execute frame and the values after the execution are returned in the call frame. 6. The minimum transfer is 1 byte the maximum transfer is 1024 bytes, except for OS STD frames for which the maximum is 128 bytes. 7. Atari memory area 2000-38FF is available for CPM users. 8. For DISK type OS calls, the byte count is ignored before execution, all disk transfers are one sector at a time. The byte count, after reads, contains the number of bytes actually in that sector. 9. FX will be set to the value of the CH (KEY) register for STD-OS calls, a value of FF indicates no key depressed. 10. For Status Commands on output devices, a FSTAT return of 01 implies that the device can accept a character. The DEV STATUS bytes will only be valid if the Device Code is not set for immediate return. 3 2 Quote Link to comment Share on other sites More sharing options...
ivop Posted April 2 Share Posted April 2 (edited) Here's the Atari side of things. This is the main loop that runs to handle requests made by CP/M. Again (twice) they use self-modifying code. See JSR DUMMY. I did not convert weird syntax to mads, like LDA X,LABEL but it's readable as it is. BTW some of their tools seem to be hidden in the CPMFILES* hexdumps. No Z80 source code though. cpmmain.asm Edited April 2 by ivop 2 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.