diff --git a/README.md b/README.md index 5337b49..b67c0fb 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,6 @@ $ cpmcp -f sanco SANCO8003_CPM_2.2fr.bin "0:*" disk/ $ cpmcp -f sanco SANCO8003_CPM_2.2fr.bin test.bin "0:TEST.COM" ``` -## Other contributions - -- [RetroNewbie/Sanco_8000](https://github.com/RetroNewbie/Sanco_8000/tree/main/CP-M), some disassemblies of the software inside in this floppy. - ## External references - [CP/M BIOS documentation](https://www.seasip.info/Cpm/bios.html). diff --git a/applications/FMT8003.COM.asm b/applications/FMT8003.COM.asm new file mode 100644 index 0000000..9d03a4e --- /dev/null +++ b/applications/FMT8003.COM.asm @@ -0,0 +1,1598 @@ +; This is the disassembly of the "FMT8003.COM" program for the Sanco 8003 +; found in the CP/M 2.2 image at this link: +; https://archive.org/details/sanco-8003-cpm-2.2fr.dsqd +; +; By Giulio Venturini (@BayoDev) + + ORG $0100 + +l0100: + ld sp,l0100 ;[0100] + call OUT_STRING ;[0103] + + DB $0D + DB $0A + DB "iBEX 8003 Formatter Version 1.0" + DB $0D + DB $0A + DB "1024 BYTE/SECTOR" + DB $00 + +DRIVE_SEL_PROMPT: + call OUT_STRING ;[013c] + + DB $0D + DB $0A + DB $0A + DB "INITIALIZE (A-B)? " + DB $00 + + call IN_LINE ;[0155] + ld a,(l02d8) ;[0158] Get lenght of input string + or a ;[015b] + jp z,RST_FLOPPY_AND_CPM ;[015c] Exit program if the input string is empty + cp $02 ;[015f] + jr nc,DRIVE_SEL_PROMPT ;[0161] Jump if the input string is > 2 char long + ld a,(l02d9) ;[0163] Load first input char + res 5,a ;[0166] Reset 5th bit of the A register + ld (l0198),a ;[0168] Change the next string to display the drive letter + cp $41 ;[016b] Check if input == 'A' + jr c,DRIVE_SEL_PROMPT ;[016d] Jump if the input is < than 'A' (Invalid input) + cp $43 ;[016f] Check if input == 'B' + jr nc,DRIVE_SEL_PROMPT ;[0171] Jump if the input is > than 'B' (Invalid input) + dec a ;[0173] + and $03 ;[0174] + ld (DRIVE_SEL),a ;[0176] Save drive selection in memory +l0179: + call OUT_STRING ;[0179] + + DB $0D + DB $0A + DB "INSERT NEW DISKETTE DRIVE " +l0198: + DB $00 ;[0198] This will contain the drive letter + DB $3A + DB $0D + DB $0A + DB "THEN READY,TYPE RETURN" + DB $00 + + call IN_CHAR ;[01b3] + cp $03 ;[01b6] + jp z,RST_FLOPPY_AND_CPM ;[01b8] Jump if input==0x03 (End of text) + cp $0d ;[01bb] + jp nz,DRIVE_SEL_PROMPT ;[01bd] Jump if input!=0x0D (Carriage return) + call OUT_STRING ;[01c0] Print new line + + DB $0D + DB $0A + DB $00 + + xor a ;[01c6] Resets register A + ld (TRACK_CUR),a ;[01c7] Set the current track to $00 + ld a,$08 ;[01ca] + ld (l03e8),a ;[01cc] Set l03e8 to $08 + call ZERO_SEEK ;[01cf] +FORMAT_LOOP: + call L0373 ;[01d2] + call OUT_DISK_TRACE ;[01d5] + call FORMAT_TRACK ;[01d8] + ld a,(DRIVE_SEL) ;[01db] + bit 2,a ;[01de] + jr nz,l01ea ;[01e0] + set 2,a ;[01e2] + ld (DRIVE_SEL),a ;[01e4] Set DRIVE_SEL[2] to 1 if not already + jp FORMAT_LOOP ;[01e7] +l01ea: + res 2,a ;[01ea] Reset 2nd bit of DRIVE_SEL + ld (DRIVE_SEL),a ;[01ec] + ld a,(TRACK_CUR) ;[01ef] + inc a ;[01f2] + ld (TRACK_CUR),a ;[01f3] Increase current track + cp $50 ;[01f6] Check if end of tracks + jp z,START_VERIFY ;[01f8] Jump if end of tracks reached + call MOVE_HEAD ;[01fb] Move head to current track + jp FORMAT_LOOP ;[01fe] + +START_VERIFY: + call OUT_STRING ;[0201] + + DB $0D + DB $0A + DB "VERIFY START" + DB $00 + + ld ix,l040d ;[0213] + ld a,(DRIVE_SEL) ;[0217] + and $03 ;[021a] + ld (ix+$00),a ;[021c] (l040d) = DRIVE_SEL[0:1] + ld (ix+$01),$28 ;[021f] + ld (ix+$02),$10 ;[0223] + ld (ix+$03),$05 ;[0227] + ld (ix+$04),$01 ;[022b] + ld (ix+$05),$03 ;[022f] + call READ_DISK ;[0233] + cp $ff ;[0236] + jp z,VERIFY_ERROR ;[0238] Jump if READ_DISK failed + call OUT_STRING ;[023b] Print confirmation string + + DB $0D + DB $0A + DB "VERIFY COMPLETED" + DB $00 + + jp l0179 ;[0251] Jump back to disk insertion + +VERIFY_ERROR: + push de ;[0254] + call OUT_STRING ;[0255] + + DB $0D + DB $0A + DB $07 + DB "VERIFY ERROR!" + DB $00 + + pop de ;[0269] + push de ;[026A] + call OUT_STRING ;[026B] Print track where the error occurred + + DB $0D + DB $0A + DB "TRACK " + DB $00 + + ld e,d ;[0278] + call OUT_DEC ;[0279] + call OUT_STRING ;[027c] Print side where the error occurred + + DB $0D + DB $0A + DB "SIDE " + DB $00 + + ld a,b ;[0289] + and $04 ;[028a] + rrca ;[028c] + rrca ;[028d] + or $30 ;[028e] + ld e,a ;[0290] + call OUT_CHAR ;[0291] + call OUT_STRING ;[0294] Print sector where the error occurred + + DB $0D + DB $0A + DB "SECTOR " + DB $00 + + pop de ;[02a1] + call OUT_DEC ;[02a2] + jp RST_FLOPPY_AND_CPM ;[02a5] + +; Converts the E register from binary to decimal and then +; prints it +OUT_DEC: + push bc ;[02a8] + push de ;[02a9] + ld a,e ;[02aa] + ld b,$0a ;[02ab] + ld c,$ff ;[02ad] +l02af: + inc c ;[02af] + sub b ;[02b0] + jr nc,l02af ;[02b1] Subtract $0a from the A register and increment C until A<0 + add b ;[02b3] In the end this is A=A%B and C=A/B + ld b,a ;[02b4] + ld a,c ;[02b5] + or $30 ;[02b6] Binary number to ASCII + ld e,a ;[02b8] + call OUT_CHAR ;[02b9] Print second decimal digit (most significant) + ld a,b ;[02bc] + or $30 ;[02bd] Binary number to ASCII + ld e,a ;[02bf] + call OUT_CHAR ;[02c0] Print first decimal digit + pop de ;[02c3] + pop bc ;[02c4] + ret ;[02c5] + +; Use the bdos call to read from keyboard until RETURN is pressed +IN_LINE: + push af ;[02c6] + push bc ;[02c7] + push de ;[02c8] + push hl ;[02c9] + ld de,l02d7 ;[02ca] + ld c,$0a ;[02cd] + call $0005 ;[02cf] + pop hl ;[02d2] + pop de ;[02d3] + pop bc ;[02d4] + pop af ;[02d5] + ret ;[02d6] + +; Text input buffer used in the IN_LINE function +l02d7: + DB $0a ;[02d7] +l02d8: + DB $b8 ;[02d8] +l02d9: + DB $00 ;[02d9] + DB $00 ;[02da] + DB $00 ;[02db] + DB $00 ;[02dc] + DB $00 ;[02dd] + DB $00 ;[02de] + DB $00 ;[02df] + DB $00 ;[02e0] + DB $00 ;[02e1] + DB $00 ;[02e2] + + call OUT_STRING ;[02e3] + + DB "ERR" + DB $00 + + jr RST_FLOPPY_AND_CPM ;[02ea] + +RST_FLOPPY_AND_CPM: + call ZERO_SEEK ;[02ec] +CPM_RST: + ld c,$00 ;[02ef] + jp $0005 ;[02f1] Issue bdos call for system reset + +ZERO_SEEK: + ld b,$00 ;[02f4] Set "move to track 0" operation + ld a,(DRIVE_SEL) ;[02f6] + ld c,a ;[02f9] Set drive number + call FDC_WRAPPER ;[02fa] Call ROM routine + cp $ff ;[02fd] + ret nz ;[02ff] Return if A!=$FF + call OUT_STRING ;[0300] Print error + + DB $0D + DB $0A + DB "ZERO SEEK ERROR!" + DB $00 + + jp CPM_RST ;[0339] + +; Move head to the track TRACK_CUR +MOVE_HEAD: + ld b,$20 ;[0319] + ld a,(TRACK_CUR) ;[031b] + ld d,a ;[031e] + ld a,(DRIVE_SEL) ;[031f] + ld c,a ;[0322] + call FDC_WRAPPER ;[0323] + cp $ff ;[0326] + ret nz ;[0328] Jump if everything went good + call OUT_STRING ;[0329] Print error and reset CP/M if failed + + DB $0D + DB $0A + DB "SEEK ERROR!" + DB $00 + + jp CPM_RST ;[0370] + +FORMAT_TRACK: + ld b,$f0 ;[033d] B=$f0 (command for format operation) + ld a,(DRIVE_SEL) ;[033f] + ld c,a ;[0342] C = DRIVE_SEL + ld a,(TRACK_CUR) ;[0343] + ld d,a ;[0346] D = TRACK_CUR + or a ;[0347] + jr nz,l0352 ;[0348] Jump if TRUCK_CUR!=0 + bit 2,c ;[034a] + jr nz,l0352 ;[034c] Jump if DRIVE_SEL[2] != 0 + ld a,$01 ;[034e] + jr l0354 ;[0350] +l0352: + ld a,$03 ;[0352] If DRIVE_SEL[2]==1 -> A=$03 , ELSE -> A=$01 +l0354: + ld hl,$5000 ;[0354] Address where the + call FDC_WRAPPER ;[0357] Call sanco's FDC routine for "format desired track" + cp $ff ;[035a] + ret nz ;[035c] Return FDC routine didn't fail + call OUT_STRING ;[035d] Otherwise print error + + DB $0D + DB $0A + DB "FORMAT ERROR!" + DB $00 + + jp CPM_RST ;[0370] + +; ??????? +L0373: + ld hl,$5000 ;[0373] + ld e,$01 ;[0376] + ld a,(DRIVE_SEL) ;[0378] Load drive number + and $04 ;[037b] + rrca ;[037d] + rrca ;[037e] + ld b,a ;[037f] byte 2 of DRIVE_SEL becomes byte 0 of B + ld a,(TRACK_CUR) ;[0380] + ld d,a ;[0383] + or a ;[0384] + jr nz,l0392 ;[0385] Jump if TRACK_CUR!=0 + bit 0,b ;[0387] Test DRIVE_SEL[2] + jr nz,l0392 ;[0389] Jump if !=0 (i.e. =1) + ld c,$01 ;[038b] + ld a,$10 ;[038d] Write 16 times with C=$01 + jp l0396 ;[038f] +l0392: + ld a,$05 ;[0392] + ld c,$03 ;[0394] Write 5 times with C=$03 +l0396: + ld (hl),d ;[0396] Load TRACK_CUR + inc hl ;[0397] + ld (hl),b ;[0398] Load DRIVE_SEL[2] + inc hl ;[0399] + ld (hl),e ;[039a] Load counter + inc hl ;[039b] + ld (hl),c ;[039c] Load C (depenging on DRIVE_SEL[2] $01 or $03) + inc hl ;[039d] + inc e ;[039e] Increase counter + dec a ;[039f] Decrease limit + jp nz,l0396 ;[03a0] Jump if limit!=0 + ret ;[03a3] + +FDC_WRAPPER: + call $ffa3 ;[03a4] + call $c018 ;[03a7] + call $ffa6 ;[03aa] + ret ;[03ad] + + +OUT_DISK_TRACE: + call OUT_STRING ;[03ae] + +; Print current track + DB "T" + DB $00 + + ld a,(TRACK_CUR) ;[03b3] + ld e,a ;[03b6] + call OUT_DEC ;[03b7] + call OUT_STRING ;[03ba] + +; Print current side + DB $20 + DB "S" + DB $00 + + ld a,(DRIVE_SEL) ;[03c0] + and $04 ;[03c3] + rrca ;[03c5] + rrca ;[03c6] + or $30 ;[03c7] + ld e,a ;[03c9] + call OUT_CHAR ;[03ca] + call OUT_STRING ;[03cd] + + DB $20 ;" " + DB $20 ;" " + DB $20 ;" " + DB $00 + + ld a,(l03e8) ;[03d4] + dec a ;[03d7] Decrement line counter + ld (l03e8),a ;[03d8] + ret nz ;[03db] return if line counter != 0 + ld a,$08 ;[03dc] + ld (l03e8),a ;[03de] Set (l03e8) to $08 again + call OUT_STRING ;[03e1] + + DB $0D + DB $0A + DB $00 + + ret + +l03e8: + DB $3A ;[03e8] + +; This funcion keeps printing characters starting from the address where +; the function was called + 1 until it encounters $00 +OUT_STRING: + EX (SP),HL ;[03e9] +l03ea: + ld a, (hl) ;[03ea] + inc hl ;[03eb] + or a ;[03ec] + jr z,l03f5 ;[03ed] + ld e,a ;[03ef] + call OUT_CHAR ;[03f0] + jr l03ea ;[03f3] +l03f5: + ex (sp),hl ;[03f5] + ret ;[03f6] + +; Use the bdos call to print to console the ascii character +; stored in the E register +OUT_CHAR: + push af ;[03f7] + push bc ;[03f8] + push de ;[03f9] + push hl ;[03fa] + ld c,$02 ;[03fb] + call $0005 ;[03fd] + pop hl ;[0400] + pop de ;[0401] + pop bc ;[0402] + pop af ;[0403] + ret ;[0404] + +; Use the bdos call to input an ascii character from the console +; and stores it in register A and L +IN_CHAR: + ld c,$01 ;[0405] + call $0005 ;[0407] + ret ;[040a] + + +TRACK_CUR: + DB 00 ;[040b] +DRIVE_SEL: +; Drive selection(A: 0x00 or B: 0x01)[0:1], Side selection (?) [2] + DB 00 ;[040c] + +; Reference values used in the verification process +l040d: + DB 00 ;[040d] $XX Drive selection (Same format as DRIVE_SEL) + DB 00 ;[040e] $28 Max number of tracks + DB 00 ;[040f] $10 Sectors/track in side 0 + DB 00 ;[0410] $05 Sectors/track in side 1 + DB 00 ;[0411] $01 Bps shift factor in side 0 (256 byte/sector) + DB 00 ;[0412] $03 Bps shift factor in side 1 (1024 byte/sector) + +READ_DISK: + ld a,(ix+$00) ;[0413] + ld (l04ba),a ;[0416] (l04ba) = selected drive = (DRIVE_SEL[0:1]) + xor a ;[0419] + ld (l04b5),a ;[041a] Set (l04b5) = $00 +l041d: + call READ_TRACK ;[041d] + or a ;[0420] + ret nz ;[0421] Return if A!=$00 (failed) + ld a,(l04ba) ;[0422] + bit 2,a ;[0425] + jr nz,l0431 ;[0427] + set 2,a ;[0429] + ld (l04ba),a ;[042b] + jp l041d ;[042e] +l0431: + res 2,a ;[0431] + ld (l04ba),a ;[0433] Invert side bit of select drive + ld a,(l04b5) ;[0436] + inc a ;[0439] + ld (l04b5),a ;[043a] Increase current track + ld b,a ;[043d] + ld a,(ix+$01) ;[043e] + cp b ;[0441] + jp nz,l041d ;[0442] Jump if current track != number of sectors ($28) + xor a ;[0445] + ret ;[0446] Return A=$00 + +READ_TRACK: + xor a ;[0447] Reset A + ld (l04b6),a ;[0448] Set (l04b6) (i.e. current sector) = $00 + ld a,(ix+$03) ;[044b] + ld (l04b7),a ;[044e] Set (l04b7) (i.e. max sector) = (l0410) = $05 + ld a,(ix+$05) ;[0451] + ld (l04b8),a ;[0454] Set (l04b8) (i.e. bts shift factor) = (l0412) + ld b,$43 ;[0457] ?? + ld a,(l04b5) ;[0459] + or a ;[045c] + jp nz,l0474 ;[045d] Jump if (l04b5) (i.e. current track) == $00 + ld a,(l04ba) ;[0460] + bit 2,a ;[0463] + jp nz,l0474 ;[0465] Jump if (l04ba)[2]!=0 (Should be == DRIVE_SEL[2] so side select (?)) + ld a,(ix+$02) ;[0468] + ld (l04b7),a ;[046b] Set (l04b7) (i.e. number of sectors) = (l040f) = $10 + ld a,(ix+$04) ;[046e] + ld (l04b8),a ;[0471] Set (l04b8) = (l0411) = bps shift factor = $01 +l0474: + ld b,$40 ;[0474] Set operation command for sanco's routine (read sector in the HL buffer) + ld a,(l04ba) ;[0476] + ld c,a ;[0479] c = drive number = (l04ba) + ld a,(l04b5) ;[047a] + ld d,a ;[047d] d = current track = (l04b5) + ld a,(l04b6) ;[047e] + ld e,a ;[0481] e = current sector = (l04b6) + ld hl,$04bb ;[0482] hl = read buffer address = $04bb + ld a,(l04b8) ;[0485] a = bytes per sector shift factor = (l04b8) + call $ffa3 ;[0488] + call $c018 ;[048b] Use sanco's routine to read sector in the HL buffer + call $ffa6 ;[048e] + or a ;[0491] + jp nz,READ_TRACK_ERR ;[0492] Jump if a!=0 <=> failed sanco's routine + ld a,(l04b6) ;[0495] + inc a ;[0498] + ld (l04b6),a ;[0499] Increase (l04b6) = current sector + ld b,a ;[049c] + ld a,(l04b7) ;[049d] + cp b ;[04a0] + jp nz,l0474 ;[04a1] Jump if sector!=number of sectors + xor a ;[04a4] A = 0 + ret ;[04a5] return + +READ_TRACK_ERR: + ld a,(l04b5) ;[04a6] + ld d,a ;[04a9] d = current track + ld a,(l04b6) ;[04aa] + ld e,a ;[04ad] e = current sector + ld a,(l04ba) ;[04ae] + ld b,a ;[04b1] b = drive number + ld a,$ff ;[04b2] a = $ff + ret ;[04b4] + +; Used in the verify process +l04b5: + DB $7a ;[04b5] Current track +l04b6: + DB $b3 ;[04b6] Current sector +l04b7: + DB $2f ;[04b7] Number of sectors +l04b8: + DB $ca ;[04b8] Bytes per sector, shift factor + DB $35 ;[04b9] Seems to be unused +l04ba: + DB $29 ;[04ba] Drive number + + +; From now on this is used as a data section used +; to store data from the READ_TRACK routine + + DB $AF + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $3A ;':' + DB $D1 + DB $3C ;'<' + DB $CD + DB $3A ;':' + DB $0B + DB $3D ;'=' + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $3A ;':' + DB $D1 + DB $3C ;'<' + DB $CD + DB $3A ;':' + DB $0B + DB $B7 + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $F6 + DB $37 ;'7' + DB $F5 + DB $3A ;':' + DB $0D + DB $3D ;'=' + DB $B7 + DB $CA + DB $BD + DB $29 ;')' + DB $CD + DB $4F ;'O' + DB $0B + DB $CD + DB $1E + DB $0C + DB $C2 + DB $A5 + DB $29 ;')' + DB $E6 + DB $A0 + DB $C2 + DB $B0 + DB $29 ;')' + DB $CD + DB $08 + DB $0C + DB $CA + DB $B0 + DB $29 ;')' + DB $F1 + DB $9F + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $F1 + DB $3F ;'?' + DB $9F + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $3A ;':' + DB $0D + DB $3D ;'=' + DB $B7 + DB $C2 + DB $A9 + DB $28 ;'(' + DB $C1 + DB $AF + DB $21 ;'!' + DB $85 + DB $0D + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $C3 + DB $35 ;'5' + DB $29 ;')' + DB $F6 + DB $37 ;'7' + DB $F5 + DB $CD + DB $17 + DB $2A ;'*' + DB $C2 + DB $BD + DB $29 ;')' + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $78 ;'x' + DB $B1 + DB $CA + DB $B0 + DB $29 ;')' + DB $C3 + DB $AB + DB $29 ;')' + DB $F6 + DB $37 ;'7' + DB $F5 + DB $CD + DB $17 + DB $2A ;'*' + DB $C2 + DB $BD + DB $29 ;')' + DB $D5 + DB $C5 + DB $7E ;'~' + DB $FE + DB $2C ;',' + DB $C2 + DB $0F + DB $2A ;'*' + DB $23 ;'#' + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $CD + DB $17 + DB $2A ;'*' + DB $C2 + DB $12 + DB $2A ;'*' + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $79 ;'y' + DB $C1 + DB $E1 + DB $B9 + DB $C2 + DB $AB + DB $29 ;')' + DB $1A + DB $BE + DB $C2 + DB $AB + DB $29 ;')' + DB $13 + DB $23 ;'#' + DB $0D + DB $C2 + DB $01 + DB $2A ;'*' + DB $C3 + DB $B0 + DB $29 ;')' + DB $CD + DB $BB + DB $04 + DB $E1 + DB $E1 + DB $C3 + DB $BD + DB $29 ;')' + DB $CD + DB $C2 + DB $0B + DB $FE + DB $3C ;'<' + DB $C4 + DB $97 + DB $04 + DB $CD + DB $1D + DB $0B + DB $B7 + DB $C2 + DB $37 ;'7' + DB $2A ;'*' + DB $CD + DB $E4 + DB $0A + DB $CD + DB $1D + DB $0B + DB $FE + DB $26 ;'&' + DB $C2 + DB $37 ;'7' + DB $2A ;'*' + DB $CD + DB $E4 + DB $0A + DB $C3 + DB $1F + DB "**+=+" + DB $11 + DB $00 + DB $00 + DB $23 ;'#' + DB $7E ;'~' + DB $FE + DB $3E ;'>' + DB $C2 + DB $47 ;'G' + DB $2A ;'*' + DB $54 ;'T' + DB $5D ;']' + DB $FE + DB $2C ;',' + DB $C2 + DB $51 ;'Q' + DB $2A ;'*' + DB $7A ;'z' + DB $B3 + DB $C2 + DB $57 ;'W' + DB $2A ;'*' + DB $FE + DB $0D + DB $C2 + DB $3E ;'>' + DB $2A ;'*' + DB $23 ;'#' + DB $E5 + DB $2A ;'*' + DB $2B ;'+' + DB $3D ;'=' + DB $7A ;'z' + DB $B3 + DB $CC + DB $97 + DB $04 + DB $EB + DB $7D ;'}' + DB $93 + DB $4F ;'O' + DB $7C ;'|' + DB $9A + DB $47 ;'G' + DB $E1 + DB $3A ;':' + DB $F6 + DB $3D ;'=' + DB $FE + DB $20 ;' ' + DB $C9 + DB $CD + DB $4F ;'O' + DB $0B + DB $4F ;'O' + DB $C5 + DB $C4 + DB $97 + DB $04 + DB $37 ;'7' + DB $CD + DB $F6 + DB $0C + DB $23 ;'#' + DB $7E ;'~' + DB $F6 + DB $40 ;'@' + DB $77 ;'w' + DB $C1 + DB $E6 + DB $20 ;' ' + DB $CC + DB $D3 + DB $04 + DB $7E ;'~' + DB $E6 + DB $80 + DB $C4 + DB $AF + DB $04 + DB $1F + DB $1F + DB $1F + DB $B6 + DB $77 ;'w' + DB $79 ;'y' + DB $FE + DB $2C ;',' + DB $CA + DB $6E ;'n' + DB $2A ;'*' + DB $C9 + DB $11 + DB $16 + DB $3E ;'>' + DB $01 + DB $00 + DB $4F ;'O' + DB $C3 + DB $A7 + DB $2A ;'*' + DB $0E + DB $00 + DB $11 + DB $66 ;'f' + DB $3E ;'>' + DB $06 + DB $3B ;';' + DB $CD + DB $C2 + DB $0B + DB "*+=+~#" + DB $FE + DB $0D + DB $CA + DB $C4 + DB $2A ;'*' + DB $B9 + DB $CA + DB $C4 + DB $2A ;'*' + DB $04 + DB $05 + DB $CA + DB $AE + DB $2A ;'*' + DB $12 + DB $13 + DB $05 + DB $C3 + DB $AE + DB $2A ;'*' + DB $AF + DB $12 + DB $23 ;'#' + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $C9 + DB $CD + DB $C2 + DB $0B + DB $FE + DB $28 ;'(' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $23 ;'#' + DB $0B + DB $FE + DB $27 ;''' + DB $C2 + DB $97 + DB $04 + DB $4F ;'O' + DB $CD + DB $A2 + DB $2A ;'*' + DB $CD + DB $30 ;'0' + DB $0B + DB $CD + DB $23 ;'#' + DB $0B + DB $FE + DB $29 ;')' + DB $C4 + DB $97 + DB $04 + DB $C3 + DB $3A ;':' + DB $0B + DB $3E ;'>' + DB $01 + DB $32 ;'2' + DB $14 + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $AF + DB $32 ;'2' + DB $14 + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $AF + DB $32 ;'2' + DB $12 + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $CD + DB $4F ;'O' + DB $0B + DB $C2 + DB $29 ;')' + DB $2B ;'+' + DB $0C + DB $0D + DB $CA + DB $29 ;')' + DB $2B ;'+' + DB $F5 + DB $CD + DB $08 + DB $0C + DB $C4 + DB $1E + DB $0C + DB $C2 + DB $1C + DB $2B ;'+' + DB $7E ;'~' + DB $F6 + DB $40 ;'@' + DB $77 ;'w' + DB $F1 + DB $FE + DB $2C ;',' + DB $C0 + DB $CD + DB $4F ;'O' + DB $0B + DB $C2 + DB $BB + DB $04 + DB $C3 + DB $0E + DB $2B ;'+' + DB $3E ;'>' + DB $01 + DB $32 ;'2' + DB $12 + DB $3D ;'=' + DB $C9 + DB $3E ;'>' + DB $FF + DB $32 ;'2' + DB $13 + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $AF + DB $32 ;'2' + DB $13 + DB $3D ;'=' + DB $C3 + DB $3A ;':' + DB $0B + DB $3E ;'>' + DB $01 + DB $32 ;'2' + DB $13 + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $AF + DB $C3 + DB $5F ;'_' + DB $2B ;'+' + DB $3E ;'>' + DB $FF + DB $C3 + DB "_+:r@/o:" + DB $D1 + DB $3C ;'<' + DB $B7 + DB $CA + DB ";+}2r@2" + DB $0F + DB $3D ;'=' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $3E ;'>' + DB $01 + DB $32 ;'2' + DB $CF + DB $3C ;'<' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $AF + DB $32 ;'2' + DB $CF + DB $3C ;'<' + DB $C3 + DB $3B ;';' + DB $2B ;'+' + DB $3E ;'>' + DB $FF + DB $32 ;'2' + DB $D7 + DB $3C ;'<' + DB $CD + DB $A9 + DB $28 ;'(' + DB $AF + DB $32 ;'2' + DB $D7 + DB $3C ;'<' + DB $7A ;'z' + DB $B7 + DB $C2 + DB $97 + DB $04 + DB $3A ;':' + DB $F6 + DB $3D ;'=' + DB $FE + DB $20 ;' ' + DB $C0 + DB $7B ;'{' + DB $3D ;'=' + DB $F8 + DB $CA + DB $97 + DB $04 + DB $FE + DB $10 + DB $D2 + DB $97 + DB $04 + DB $3C ;'<' + DB $32 ;'2' + DB $D6 + DB $3C ;'<' + DB $AF + DB $67 ;'g' + DB $6B ;'k' + DB $C3 + DB $2E ;'.' + DB $1B + DB $CD + DB $A9 + DB $28 ;'(' + DB $7A ;'z' + DB $B7 + DB $C2 + DB $97 + DB $04 + DB $3A ;':' + DB $D1 + DB $3C ;'<' + DB $B7 + DB $C8 + DB $7B ;'{' + DB $B7 + DB $CA + DB $C3 + DB $2B ;'+' + DB $FE + DB $0A + DB $DC + DB $97 + DB $04 + DB $3A ;':' + DB $F6 + DB $3D ;'=' + DB $FE + DB $20 ;' ' + DB $C2 + DB $C3 + DB $2B ;'+' + DB $7B ;'{' + DB $32 ;'2' + DB $17 + DB $3D ;'=' + DB $CD + DB $25 ;'%' + DB $19 + DB $CD + DB $39 ;'9' + DB $04 + DB $C3 + DB $6A ;'j' + DB $1A + DB $CD + DB $4F ;'O' + DB $0B + DB $C2 + DB $97 + DB $04 + DB $F5 + DB $3A ;':' + DB $CE + DB $3D ;'=' + DB $FE + DB $08 + DB $DA + DB $E0 + DB $2B ;'+' + DB $CD + DB $C7 + DB $04 + DB $3E ;'>' + DB $07 + DB $21 ;'!' + DB $C7 + DB $3D ;'=' + DB $77 ;'w' + DB $23 ;'#' + DB $22 ;'"' + DB $24 ;'$' + DB $3D ;'=' + DB $3A ;':' + DB $D1 + DB $3C ;'<' + DB $B7 + DB $0E + DB $03 + DB $C4 + DB $A3 + DB $1B + DB $F1 + DB $FE + DB $2C ;',' + DB $CA + DB $CC + DB $2B ;'+' + DB $C9 + DB $3A ;':' + DB $11 + DB $3D ;'=' + DB $B7 + DB $C2 + DB $BB + DB $04 + DB $CD + DB $C2 + DB $0B + DB $2A ;'*' + DB $2B ;'+' + DB $3D ;'=' + DB $2B ;'+' + DB $CD + DB $33 ;'3' + DB $4E ;'N' + DB $B7 + DB $CA + DB $13 + DB $2C ;',' + DB $CD + DB $F6 + DB $4E ;'N' + DB $C3 + DB $D9 + DB $04 + DB $3D ;'=' + DB $32 ;'2' + DB $11 + DB "=*+=~#" + DB $22 ;'"' + DB $2B ;'+' + DB $3D ;'=' + DB $FE + DB $21 ;'!' + DB $D2 + DB $17 + DB $2C ;',' + DB $C9 + DB $CD + DB $C2 + DB $0B + DB $FE + DB $28 ;'(' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $23 ;'#' + DB $0B + DB $FE + DB $27 ;''' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $4F ;'O' + DB $0B + DB $C2 + DB $97 + DB $04 + DB $FE + DB $27 ;''' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $23 ;'#' + DB $0B + DB $FE + DB $29 ;')' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $3A ;':' + DB $0B + DB $3A ;':' + DB $D1 + DB $3C ;'<' + DB $B7 + DB $C0 + DB $3A ;':' + DB $CE + DB $3D ;'=' + DB $FE + DB $06 + DB $DA + DB $5A ;'Z' + DB $2C ;',' + DB $3E ;'>' + DB $06 + DB $11 + DB $CF + DB "=!B?G~" + DB $B7 + DB $C2 + DB $AF + DB $04 + DB $1A + DB $77 ;'w' + DB $23 ;'#' + DB $13 + DB $05 + DB $C2 + DB $66 ;'f' + DB $2C ;',' + DB $70 ;'p' + DB $C9 + DB $CD + DB $B6 + DB $2C ;',' + DB $CD + DB $C2 + DB $0B + DB $FE + DB $2F ;'/' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $4F ;'O' + DB $0B + DB $C4 + DB $AE + DB $2C ;',' + DB $FE + DB $2F ;'/' + DB $C2 + DB $97 + DB $04 + DB $CD + DB $3A ;':' + DB $0B + DB $CD + DB $F6 + DB $0C + DB $23 ;'#' + DB $7E ;'~' + DB $E6 + DB $D0 + DB $C2 + DB $AF + DB $04 + DB $E5 + DB $7E ;'~' + DB $F6 + DB $24 ;'$' + DB $77 ;'w' + DB $CD + DB $17 + DB $27 ;''' + DB $E1 + DB $2B ;'+' + DB $22 ;'"' + DB $BF + DB $3D ;'=' + DB $3E ;'>' + DB $03 + DB $32 ;'2' + DB $B6 + DB $3D ;'=' + DB $21 ;'!' + DB $00 + DB $00 + DB $22 ;'"' + DB $B7 + DB $3D ;'=' + DB $C3 + DB $96 + DB $26 ;'&' + DB $F5 + DB $3E ;'>' + DB $01 + DB $32 ;'2' + DB $CE + DB $3D ;'=' + DB $F1 + DB $C9 + DB $3A ;':' + DB $C9 + DB $3D ;'=' + DB $B7 + DB $C8 + DB $C1 + DB $C3 + DB $C1 + DB $04 + DB $11 + DB $80 + DB $00 + DB $CD + DB $4F ;'O' + DB $0B + DB $C2 + DB $E8 + DB $2C ;',' + DB $F5 + DB $B7 + DB $D5 + DB $CD + DB $F6 + DB $0C + DB $CD + DB $F7 + DB $2C ;',' + DB $D1 + DB $7E ;'~' + DB $B2 + DB $77 ;'w' + DB $23 ;'#' + DB $7E ;'~' + DB $E6 + DB $64 ;'d' + DB $C2 + DB $EE + DB $2C ;',' + DB $7E ;'~' + DB $E6 + DB $03 + DB $B3 + DB $77 ;'w' + DB $F1 + DB $FE + DB $2C ;',' + DB $CA + DB $C2 + DB $2C ;',' + DB $C9 + DB $CD + DB $97 + DB $04 + DB $C3 + DB $E2 + DB $2C ;',' + DB $F6 + DB $10 + DB $77 ;'w' + DB $CD + DB $AF + DB $04 + DB $C3 + DB $E1 + DB $2C ;',' + DB $7E ;'~' + DB $FE + DB $40 ;'@' + DB $C8 + DB $FE + DB $C0 + DB $C8 + DB $E6 + DB $40 ;'@' + DB $C8 + DB $7E ;'~' + DB $AF + DB $77 ;'w' + DB $E5 + DB $AF + DB "#w#w#w" + DB $E1 + DB $C9 + DB $CD + DB $4F ;'O' + DB $0B + DB $CD + DB $0F + DB $05 + DB $7E ;'~' + DB $87 + DB $D4 + DB $BB + DB $04 + DB $23 ;'#' + DB $7E ;'~' + DB $FE + DB $10 + DB $CA + DB $25 ;'%' + DB $2D ;'-' + DB $FE + DB $0F + DB $C4 + DB $BB + DB $04 + DB $11 + DB $80 + DB $04 + DB $C3 + DB $C2 + DB $2C ;',' + DB $22 ;'"' + DB $28 ;'(' + DB $3D ;'=' + DB $CD + DB $54 ;'T' + DB $2D ;'-' + DB $3A ;':' + DB $F6 + DB $3D ;'=' + DB $32 ;'2' + DB $16 + DB $3D ;'=' + DB $FE + DB $55 ;'U' + DB $C8 + DB $78 ;'x' + DB $E6 + DB $80 + DB $C2 + DB $A9 + DB $04 + DB $78 ;'x' + DB $F6 + DB $20 ;' ' + DB $32 ;'2' + DB $15 + DB $3D ;'=' + DB $2A ;'*' + DB $28 ;'(' + DB $3D ;'=' + DB $22 ;'"' + DB $24 ;'$' + DB $3D ;'=' + DB $CD + DB $D5 + DB $0D + DB $EB + DB $78 ;'x' + DB $C3 + DB $2E ;'.' + DB $1B + DB $CD + DB $68 ;'h' + DB $20 ;' ' + DB $3A ;':' + DB $A7 + DB $3E ;'>' + DB $B7 + DB $C8 + DB $C3 + DB $C7 + DB $04 + DB $22 ;'"' + DB $28 ;'(' + DB $3D ;'=' + DB $7E ;'~' + DB $F6 + DB $80 + DB $77 ;'w' + DB $7C ;'|' + DB $32 ;'2' + DB $16 + DB $3D ;'=' + DB $CD + DB $54 ;'T' + DB $2D ;'-' + DB $78 ;'x' + DB $E6 + DB $80 + DB $C2 + DB $A9 + DB $04 + DB $2A ;'*' + DB $28 ;'(' + DB $E1 + DB $2C ;',' + DB $7E ;'~' + DB $FE + DB $40 ;'@' + DB $C8 + DB $FE + DB $C0 + DB $C8 + DB $E6 + DB $40 ;'@' + DB $C8 + DB $7E ;'~' + DB $AF + DB $77 ;'w' + DB $E5 + DB $AF + DB "#w#w#w" + DB $E1 + DB $C9 + DB $CD + DB $4F ;'O' + DB $0B + DB $CD + DB $0F + DB $05 + DB $7E ;'~' + DB $87 + DB $D4 + DB $BB + DB $04 + DB $23 ;'#' + DB $7E ;'~' + DB $FE + DB $10 + DB $CA + DB $25 ;'%' + DB $2D ;'-' + DB $FE + DB $0F + DB $C4 + DB $BB + DB $04 + DB $11 + DB $80 + DB $04 + DB $C3 + DB $C2 + DB $2C ;',' + DB $22 ;'"' + DB $28 ;'(' + DB $3D ;'=' + DB $CD + DB $54 ;'T' + DB $2D ;'-' + DB $3A ;':' + DB $F6 + DB $3D ;'=' + DB $32 ;'2' + DB $16 + DB $3D ;'=' + DB $FE + DB $55 ;'U' + DB $C8 diff --git a/applications/RCX62.COM.asm b/applications/RCX62.COM.asm new file mode 100644 index 0000000..928b10a --- /dev/null +++ b/applications/RCX62.COM.asm @@ -0,0 +1,768 @@ +; This is the disassembly of the "RCX62.COM" program for the Sanco 8003 +; found in the CP/M 2.2 image at this link: +; https://archive.org/details/sanco-8003-cpm-2.2fr.dsqd +; +; By Giulio Venturini (@BayoDev) + + org $0100 + + nop ;[0100] + nop ;[0101] + nop ;[0102] +; JUMP START + jp INIT ;[0103] + +SIO_SETUP_WRAPPER: + jp SIO_SETUP ;[0106] + +SIO_WRITE_WRAPPER: + jp SIO_WRITE ;[0109] + +SIO_READ_WRAPPER: + jp SIO_READ ;[010c] + +INIT: + ld sp,$01ac ;[010f] Setup stack pointer + call SIO_SETUP_WRAPPER ;[0112] Setup SIO + ld hl,($0001) ;[0115] + ld de,$0006 ;[0118] + add hl,de ;[011b] + ld ($01fe),hl ;[011c] ($01fe) = $0006 + call PRINT_NEXT_STR ;[011f] + DB $0d ;[0122] + DB $0a ;[0123] + DB "File exchange program vers 6.0 ,4800 Baud (SED)";[0124] + DB $0d ;[0153] + DB $0a ;[0154] + DB $0a ;[0155] + DB "Ready to receive" ;[0156] + DB $0d ;[0166] + DB $0a ;[0167] + DB $00 ;[0168] + jp RCV_FIRST ;[0169] + +; STACK SPACE START + DB $00 ;[016c] + DB $00 ;[016d] + DB $00 ;[016e] + DB $00 ;[016f] + DB $00 ;[0170] + DB $00 ;[0171] + DB $00 ;[0172] + DB $00 ;[0173] + DB $00 ;[0174] + DB $00 ;[0175] + DB $00 ;[0176] + DB $00 ;[0177] + DB $00 ;[0178] + DB $00 ;[0179] + DB $00 ;[017a] + DB $00 ;[017b] + DB $00 ;[017c] + DB $00 ;[017d] + DB $00 ;[017e] + DB $00 ;[017f] + DB $00 ;[0180] + DB $00 ;[0181] + DB $00 ;[0182] + DB $00 ;[0183] + DB $00 ;[0184] + DB $00 ;[0185] + DB $00 ;[0186] + DB $00 ;[0187] + DB $00 ;[0188] + DB $00 ;[0189] + DB $00 ;[018a] + DB $00 ;[018b] + DB $00 ;[018c] + DB $00 ;[018d] + DB $00 ;[018e] + DB $00 ;[018f] + DB $00 ;[0190] + DB $00 ;[0191] + DB $00 ;[0192] + DB $00 ;[0193] + DB $00 ;[0194] + DB $00 ;[0195] + DB $00 ;[0196] + DB $00 ;[0197] + DB $00 ;[0198] + DB $00 ;[0199] + DB $00 ;[019a] + DB $00 ;[019b] + DB $00 ;[019c] + DB $00 ;[019d] + DB $00 ;[019e] + DB $00 ;[019f] + DB $00 ;[01a0] + DB $00 ;[01a1] + DB $00 ;[01a2] + DB $00 ;[01a3] + DB $00 ;[01a4] + DB $00 ;[01a5] + DB $00 ;[01a6] + DB $00 ;[01a7] + DB $00 ;[01a8] + DB $00 ;[01a9] + DB $00 ;[01aa] + DB $00 ;[01ab] +; STACK SPACE END + +; Data buffer for filename (?) + DB $00 ;[01ac] + DB $00 ;[01ad] + DB $00 ;[01ae] + DB $00 ;[01af] + DB $00 ;[01b0] + DB $00 ;[01b1] + DB $00 ;[01b2] + DB $00 ;[01b3] + DB $00 ;[01b4] + DB $00 ;[01b5] + DB $00 ;[01b6] + DB $00 ;[01b7] + DB $00 ;[01b8] + DB $00 ;[01b9] + DB $00 ;[01ba] + DB $00 ;[01bb] + +; FCB file structure + DB $00 ;[01bc] + DB $00 ;[01bd] + DB $00 ;[01be] + DB $00 ;[01bf] + DB $00 ;[01c0] + DB $00 ;[01c1] + DB $00 ;[01c2] + DB $00 ;[01c3] + DB $00 ;[01c4] + DB $00 ;[01c5] + DB $00 ;[01c6] + DB $00 ;[01c7] + DB $00 ;[01c8] + DB $00 ;[01c9] + DB $00 ;[01ca] + DB $00 ;[01cb] + DB $00 ;[01cc] + DB $00 ;[01cd] + DB $00 ;[01ce] + DB $00 ;[01cf] + DB $00 ;[01d0] + DB $00 ;[01d1] + DB $00 ;[01d2] + DB $00 ;[01d3] + DB $00 ;[01d4] + DB $00 ;[01d5] + DB $00 ;[01d6] + DB $00 ;[01d7] + DB $00 ;[01d8] + DB $00 ;[01d9] + DB $00 ;[01da] + DB $00 ;[01db] + DB $00 ;[01dc] + DB $00 ;[01dd] + DB $00 ;[01de] + +; This routine prints all the characters after the "call" function until it encounters a $00 +; When that happens the call resume execution from after the $00 +PRINT_NEXT_STR: + ex (sp),hl ;[01df] HL will contain the address where the routine was called (+1) + ld a,(hl) ;[01e0] Read the content of HL + inc hl ;[01e1] Increment address + ex (sp),hl ;[01e2] Put the address back on the stack + or a ;[01e3] + ret z ;[01e4] If A=$00 return + call C_WRITE ;[01e5] + jp PRINT_NEXT_STR ;[01e8] + +; Output A to console +C_WRITE: + push af ;[01eb] + push hl ;[01ec] + push bc ;[01ed] + push de ;[01ee] + ld c,$02 ;[01ef] + ld e,a ;[01f1] + call $0005 ;[01f2] + pop de ;[01f5] + pop bc ;[01f6] + pop hl ;[01f7] + pop af ;[01f8] + ret ;[01f9] + +; ??? +L01FA: + push bc ;[01fa] + push de ;[01fb] + push hl ;[01fc] + + call $0000 ;[01fd] This will be modified (INIT) + + pop hl ;[0200] + pop de ;[0201] + pop bc ;[0202] + ret ;[0203] + +;================================ +; FILE SYSCALLS +;================================ + +F_OPEN: + ld c,$0f ;[0204] + jp $0005 ;[0206] + +F_WRITE: + ld c,$15 ;[0209] + jp $0005 ;[020b] + +F_CLOSE: + ld c,$10 ;[020e] + jp $0005 ;[0210] + +F_READ: + ld c,$14 ;[0213] + jp $0005 ;[0215] + +F_MAKE: + ld c,$16 ;[0218] + jp $0005 ;[021a] + +F_DELETE: + ld c,$13 ;[021d] + jp $0005 ;[021f] + +F_RENAME: + ld c,$17 ;[0222] + jp $0005 ;[0224] + +;================================ + +; This routine is used to receive and save to file all the data +; Algorithm: +; 1) 128 blocks of 128 bytes each are read. After a full block is received +; a special character is expected: +; - ($17) a kind of acknowledge +; - ($04) this signal that it was the last block of the file +; If none of these signal is received an error occured +; 2) After the 128 blocks are received (or $04 encountered) the blocks are written to the file with FCB in $005c +; if a block that is being written is followed by $04 the file is closed. Otherwise go to step (3) +; 3) The transmitter will be waiting for the receiver to write everything to the file so +; if 128 blocks were written and the file was not complete an acknowledgment ($06) is sent to the transmitter +; to resume transmission and the algorithm keep reading from step (1) +RCV_SAVE_FILE: + ld b,$80 ;[0227] + ld hl,$1400 ;[0229] Setup pointer to memory buffer +; Read 128 blocks of 128 bytes (unless file is shorter) +READ_BLOCK_LOOP: + push bc ;[022c] + ld b,$80 ;[022d] Setup loop counter +; Read 128 bytes from the SIO into memory starting from $1400 +READ_128_LOOP: + call SIO_READ_WRAPPER ;[022f] Read value from SIO + ld (hl),a ;[0232] Store value in HL + inc hl ;[0233] HL++ + djnz READ_128_LOOP ;[0234] B-- and loop if B!=$00 + call SIO_READ_WRAPPER ;[0236] + ld (hl),a ;[0239] Read value from SIO and store in buffer + inc hl ;[023a] + cp $17 ;[023b] + pop bc ;[023d] + jp z,$0249 ;[023e] Jump if value from SIO is $17 (expected control char) + cp $04 ;[0241] + jp z,$024b ;[0243] Jump if value from SIO is $04 (end of transmission) + jp nz,FILE_TRANSFER_ERROR ;[0246] If neither $17 or $04 error + djnz READ_BLOCK_LOOP ;[0249] + ld b,$80 ;[024b] Reset loop counter for number of blocks + ld hl,$1400 ;[024d] Reset data buffer to start +WRITE_BLOCKS_LOOP: + push bc ;[0250] + ld bc,$0080 ;[0251] + ld de,$0080 ;[0254] + ldir ;[0257] Move 128 bytes from data buffer to $0080 + ld a,(hl) ;[0259] Get control character + cp $17 ;[025a] + jp nz,END_CLOSE_FILE ;[025c] Jump if that was the last block + push hl ;[025f] + push bc ;[0260] + push de ;[0261] + ld de,$005c ;[0262] Load FCB pointer + call F_WRITE ;[0265] Write block to file + pop de ;[0268] + pop bc ;[0269] + pop hl ;[026a] + or a ;[026b] + pop bc ;[026c] + jp nz,FILE_WRITE_ERROR ;[026d] Jump if error in syscall + inc hl ;[0270] HL++ + djnz WRITE_BLOCKS_LOOP ;[0271] Loop until 128 blocks + jp KEEP_RCV ;[0273] 128 blocks written without end of file + +; This routine write the last block to the file and closes it +END_CLOSE_FILE: + pop bc ;[0276] + cp $04 ;[0277] + jp nz,FILE_TRANSFER_ERROR ;[0279] If not end of file char, error + ld de,$005c ;[027c] + call F_WRITE ;[027f] Write last block to file + or a ;[0282] + jp nz,FILE_WRITE_ERROR ;[0283] jump if error in syscall + ld de,$005c ;[0286] + call F_CLOSE ;[0289] Close file + inc a ;[028c] + jp z,CLOSING_ERROR ;[028d] Jump if error in syscall + xor a ;[0290] A=0 + ret ;[0291] + +; This routine is called after 128 blocks of 128 bytes were successfully saved +; to ask the transmitter to resume transmission +KEEP_RCV: + ld a,$06 ;[0292] + call SIO_WRITE_WRAPPER ;[0294] Send acknowledge + jp RCV_SAVE_FILE ;[0297] Start receiving again + + +TRANSMISSION_END: + call PRINT_NEXT_STR ;[029a] + DB $0D ;[029b] + DB $0A ;[029c] + DB $0A ;[029d] + DB "End of transmission" ;[02a0] + DB $0D ;[02b3] + DB $0A ;[02b4] + DB $00 ;[02b5] + jp $0000 ;[02b6] EXIT FROM CP/M + +RCV_FIRST_WRAPPER: + jp RCV_FIRST ;[02b9] + + +RCV_SETUP: + call GET_FILENAME ;[02bc] Read 12 bytes in $01bd (?) (Probably read filename) + cp $03 ;[02bf] + jp nz,FILE_NAME_ERROR ;[02c1] Jump if filename didnt end with $03 (bad data) + ld hl,$01ac ;[02c4] + ld de,$005c ;[02c7] + ld bc,$0010 ;[02ca] + ldir ;[02cd] Setup the FCB for the syscalls with the input filename (in $005c) + ld de,$005c ;[02cf] + call F_OPEN ;[02d2] Open file with FCB in $005c (?) + inc a ;[02d5] + jp nz,START_RCV ;[02d6] Jump if no error in F_OPEN (file already exists) + ld de,$005c ;[02d9] + call F_MAKE ;[02dc] Create file + inc a ;[02df] + jp z,DIR_FULL_ERROR ;[02e0] Jump if error (directory full) +START_RCV: + ld de,$005c ;[02e3] + xor a ;[02e6] + ld hl,$0020 ;[02e7] + add hl,de ;[02ea] HL = $7C + ld (hl),$00 ;[02eb] ($7C) = $00 + ld de,$01bc ;[02ed] + call PRINT_FILENAME ;[02f0] Print filename located at $01bc + ld a,$06 ;[02f3] + call SIO_WRITE_WRAPPER ;[02f5] Write $06 to SIO (Acknowledge) + call RCV_SAVE_FILE ;[02f8] Receive and save file + or a ;[02fb] If routine ended correctly, A should be $00 + jp nz,FILE_ERROR ;[02fc] If A!=$00 error + ld de,$01bc ;[02ff] + call F_DELETE ;[0302] Delete file (?) + ld de,$01ac ;[0305] + call F_RENAME ;[0308] Rename file from $01ac as the file from $01bc + ld a,$20 ;[030b] + call C_WRITE ;[030d] Prints ' ' to CRT + ld a,$2a ;[0310] + call C_WRITE ;[0312] Prints '*' to CRT + ld a,$06 ;[0315] + call SIO_WRITE_WRAPPER ;[0317] Send acknowledge to SIO + jp RCV_FIRST ;[031a] Wait for new file + +; This routine gets 12 bytes from the SIO containing the filename and extension +; followed by 0x03 (end of text) +GET_FILENAME: + ld c,$0c ;[031d] + ld hl,$01bd ;[031f] +; This loop will be executed 12 times +GET_FILENAME_LOOP: + call SIO_READ_WRAPPER ;[0322] Read value from SIO (=A) + and $7f ;[0325] Remove parity (?) (Not needed for ASCII anyway) + cp $03 ;[0327] + jp z,END_FILENAME ;[0329] Check for END OF TEXT (0x03) + ld (hl),a ;[032c] (HL) = A + inc hl ;[032d] HL++ + dec c ;[032e] C-- + jp nz,GET_FILENAME_LOOP ;[032f] Loop if C!=0 + ret ;[0332] +END_FILENAME: + ld de,$01ac ;[0333] + ld hl,$01bc ;[0336] + ld bc,$0009 ;[0339] + ldir ;[033c] Move 9 bytes from $01bc to $01ac + ld hl,$01b5 ;[033e] + ld (hl),$24 ;[0341] ($01b5) = $24 + inc hl ;[0343] + ld (hl),$24 ;[0344] ($01b6) = $24 + inc hl ;[0346] + ld (hl),$24 ;[0347] ($01b7) = $24 + ret ;[0349] + + +;======================= +; ERROR MESSAGES +;======================= + +FILE_NAME_ERROR: + call PRINT_NEXT_STR ;[034a] + DB $0D ;[034d] + DB $0A ;[034e] + DB "File name error" ;[034f] + DB $00 ;[035e] + ld a,$0d ;[035f] + call SIO_WRITE_WRAPPER ;[0361] + jp RCV_FIRST ;[0364] + +DIR_FULL_ERROR: + call PRINT_NEXT_STR ;[0367] + DB $0D ;[036a] + DB $0A ;[036b] + DB "Directory full" ;[036c] + DB $00 ;[037a] + ld a,$0d ;[037b] + call SIO_WRITE_WRAPPER ;[037d] + jp RCV_FIRST ;[0380] + +FILE_TRANSFER_ERROR: + call PRINT_NEXT_STR ;[0383] + DB $0D ;[0386] + DB $0A ;[0387] + DB "File transfer error" ;[0388] + nop ;[039b] + ld a,$0d ;[039c] + call SIO_WRITE_WRAPPER ;[039e] + jp RCV_FIRST ;[03a1] + +FILE_WRITE_ERROR: + call PRINT_NEXT_STR ;[03a4] + DB $0D ;[03a7] + DB $0a ;[03a8] + DB "File write error" ;[03a9] + DB $00 ;[03b9] + ld a,$0d ;[03ba] + call SIO_WRITE_WRAPPER ;[03bc] + jp RCV_FIRST ;[03bf] + +CLOSING_ERROR: + call PRINT_NEXT_STR ;[03c2] + DB $0D ;[03c5] + DB $0A ;[03c6] + DB "Closing error" ;[03c7] + DB $00 ;[03d4] + ld a,$0d ;[03d5] + call SIO_WRITE_WRAPPER ;[03d7] + jp RCV_FIRST ;[03da] + +FILE_ERROR: + call PRINT_NEXT_STR ;[03dd] + DB $0D ;[03e0] + DB $0A ;[03e1] + DB "File error" ;[03e2] + DB $00 ;[03ec] + ld a,$0d ;[03ed] + call SIO_WRITE_WRAPPER ;[03ef] + jp RCV_FIRST ;[03f2] + + +RENAME_ERROR: + call PRINT_NEXT_STR ;[03f5] + DB $0D ;[03f8] + DB $0A ;[03f9] + DB "Rename error" ;[03fa] + DB $00 ;[0406] + ld a,$0d ;[0407] + call SIO_WRITE_WRAPPER ;[0409] + jp RCV_FIRST ;[040c] + +;======================= + +; This routine: +; 1) prints a new line (CR,LF) +; 2) prints 8 bytes starting from (de+1) +; 3) prints '.' +; 4) prints 3 bytes located after the previous 8 bytes +; i.e. prints a filename on the CRT +PRINT_FILENAME: + ld a,$0d ;[040f] + call C_WRITE ;[0411] Print 'Carriage return' to CRT + ld a,$0a ;[0414] + call C_WRITE ;[0416] Print 'Line feed' to CRT + ex de,hl ;[0419] + inc hl ;[041a] + ld b,$08 ;[041b] +PRINT_NAME: + ld a,(hl) ;[041d] A = (HL) + call C_WRITE ;[041e] Print A to CRT + inc hl ;[0421] HL++ + djnz PRINT_NAME ;[0422] Decrement B and if B!=$00 jump. (Will jump 8 times) + ld a,$2e ;[0424] + call C_WRITE ;[0426] Print '.' + ld b,$03 ;[0429] +PRINT_EXT: + ld a,(hl) ;[042b] A = (HL) + call C_WRITE ;[042c] Print A to CRT + inc hl ;[042f] HL++ + djnz PRINT_EXT ;[0430] B-- and jump if B!=$00 (Will jump 3 times) + ex de,hl ;[0432] + ret ;[0433] + +; This receives the first character of a transmission and act accordingly +RCV_FIRST: + call SIO_READ_WRAPPER ;[0434] Read an input character from the SIO (=A) + cp $18 ;[0437] + jp z,TRANSMISSION_END ;[0439] If A=$18 then end transmission and exit program + cp $11 ;[043c] + jp z,RCV_FIRST_WRAPPER ;[043e] Skip loop if A=$11 + cp $02 ;[0441] + jp z,RCV_SETUP ;[0443] If A=$02 then ready to transmit a file + cp $12 ;[0446] + call z,SIO_SETUP_WRAPPER ;[0448] if A=$12 jump + jp RCV_FIRST ;[044b] + +; Sends to port $b1 data from $0458 to $0460 (SIO SETUP) +SIO_SETUP: + ld c,$b1 ;[044e] Output port + ld b,$09 ;[0450] Number of repetitions + ld hl,SIO_SETUP_COMMANDS ;[0452] Starting address + otir ;[0455] + ret ;[0457] + +SIO_SETUP_COMMANDS: + DB $18 ;[0458] ; Reset channel 0 + DB $04 ;[0459] ; Access WR4 + DB $4c ;[045A] ; Parity Disabled, 2 stop bits (?), 8 bit sync,Data Rate x16 = Clock rate + DB $01 ;[045B] ; Access WR1 + DB $00 ;[045C] ; Disable all interrupts + DB $05 ;[045D] ; Access WR5 + DB $ea ;[045E] ; TX CRC disabled, RTS enabled, CRC-16 disabled, Transmit enabled, Send break disabled, 8 bits/character, dtr enabled + DB $03 ;[045F] ; Access WR3 + DB $c1 ;[0460] ; Receive enabled, the rest disabled, 8 bits/character + +; Write the character stored in the A register to port B of the SIO (Blocks until can transmit) +SIO_WRITE: + push af ;[0461] +SIO_WRITE_LOOP: + in a,($b1) ;[0462] + and $04 ;[0464] + jp z,SIO_WRITE_LOOP ;[0466] Loop until SIO is ready to transmit + pop af ;[0469] + out ($b0),a ;[046a] Write A to SIO + ret ;[046c] + +; Receive a character from the SIO and stores it in A (it blocks until there is something available to read) +SIO_READ: + in a,($b1) ;[046d] + and $01 ;[046f] Check if character is available to read + jp z,SIO_READ ;[0471] Loop if not + in a,($b0) ;[0474] Read character from SIO into A + ret ;[0476] + +; From now on this is unused + + ld bc,$0a0d ;[0477] + ld d,d ;[047a] + ld h,l ;[047b] + ld l,(hl) ;[047c] + ld h,c ;[047d] + ld l,l ;[047e] + ld h,l ;[047f] + ld (bc),a ;[0480] + cp $43 ;[0481] + jp nz,$0296 ;[0483] + call $0145 ;[0486] + or $04 ;[0489] + call $0151 ;[048b] + ld a,c ;[048e] + call $0151 ;[048f] + ld a,b ;[0492] + jp $0151 ;[0493] + cp $52 ;[0496] + jp nz,$0518 ;[0498] + call $011d ;[049b] + or $c0 ;[049e] + jp $0151 ;[04a0] + ld hl,($000e) ;[04a3] + push de ;[04a6] + ex de,hl ;[04a7] + ld hl,($000c) ;[04a8] + ld a,e ;[04ab] + sub l ;[04ac] + ld a,d ;[04ad] + sbc h ;[04ae] + jp nc,$02b7 ;[04af] + ld hl,($0013) ;[04b2] + ld sp,hl ;[04b5] + ret ;[04b6] + + pop de ;[04b7] + ld a,(hl) ;[04b8] + inc hl ;[04b9] + ld ($000c),hl ;[04ba] + ret ;[04bd] + + inc a ;[04be] + and $07 ;[04bf] + cp $06 ;[04c1] + jp c,$02c8 ;[04c3] + add $03 ;[04c6] + cp $05 ;[04c8] + jp c,$02cf ;[04ca] + add $02 ;[04cd] + add $41 ;[04cf] + ld c,a ;[04d1] + jp $0015 ;[04d2] + ld b,a ;[04d5] + and $f0 ;[04d6] + rrca ;[04d8] + rrca ;[04d9] + rrca ;[04da] + rrca ;[04db] + add $90 ;[04dc] + daa ;[04de] + adc $40 ;[04df] + daa ;[04e1] + ld c,a ;[04e2] + call $0015 ;[04e3] + ld a,b ;[04e6] + and $0f ;[04e7] + add $90 ;[04e9] + daa ;[04eb] + adc $40 ;[04ec] + daa ;[04ee] + ld c,a ;[04ef] + jp $0015 ;[04f0] + ld b,$04 ;[04f3] + ld c,(hl) ;[04f5] + call $0015 ;[04f6] + inc hl ;[04f9] + dec b ;[04fa] + jp nz,$02f5 ;[04fb] + ld c,$20 ;[04fe] + jp $0015 ;[0500] + ld a,d ;[0503] + and $38 ;[0504] + rrca ;[0506] + rrca ;[0507] + rrca ;[0508] + ret ;[0509] + + call $0303 ;[050a] + add a ;[050d] + ld c,a ;[050e] + ld hl,$0642 ;[050f] + add hl,bc ;[0512] + ld c,(hl) ;[0513] + call $0015 ;[0514] + inc hl ;[0517] + ld c,(hl) ;[0518] + call $0015 ;[0519] + ld c,$20 ;[051c] + call $0015 ;[051e] + jp $0015 ;[0521] + call $0303 ;[0524] + and $06 ;[0527] + cp $06 ;[0529] + jp nz,$02be ;[052b] + ld c,$53 ;[052e] + call $0015 ;[0530] + ld c,$50 ;[0533] + jp $0015 ;[0535] + call $002e ;[0538] + ld hl,($000c) ;[053b] + ld a,h ;[053e] + call $02d5 ;[053f] + ld a,l ;[0542] + call $02d5 ;[0543] + ld c,$20 ;[0546] + call $0015 ;[0548] + call $0015 ;[054b] + ret ;[054e] + + ld hl,$0000 ;[054f] + add hl,sp ;[0552] + ld ($0013),hl ;[0553] + ld a,($0010) ;[0556] + or a ;[0559] + jp z,$0371 ;[055a] + ld hl,$ffff ;[055d] + ld ($000e),hl ;[0560] + inc a ;[0563] + jp nz,$0371 ;[0564] + inc a ;[0567] + ld ($0010),a ;[0568] + ld hl,($000c) ;[056b] + jp $0397 ;[056e] + call $069e ;[0571] + jp nz,$0540 ;[0574] + ld hl,$0010 ;[0577] + ld a,(hl) ;[057a] + or a ;[057b] + jp z,FILE_TRANSFER_ERROR ;[057c] + dec (hl) ;[057f] + jp z,$0540 ;[0580] + ld hl,($000c) ;[0583] + call $06a1 ;[0586] + call $002e ;[0589] + ld c,$20 ;[058c] + call $0015 ;[058e] + call $0015 ;[0591] + call $033b ;[0594] + call $02a3 ;[0597] + ld d,a ;[059a] + ld hl,$0545 ;[059b] + ld bc,$0011 ;[059e] + cp (hl) ;[05a1] + jp z,$04fd ;[05a2] + inc hl ;[05a5] + dec c ;[05a6] + jp nz,$03a1 ;[05a7] + ld c,$0a ;[05aa] + cp (hl) ;[05ac] + jp z,$04e9 ;[05ad] + inc hl ;[05b0] + dec c ;[05b1] + jp nz,$03ac ;[05b2] + ld c,$06 ;[05b5] + cp (hl) ;[05b7] + jp z,$04ce ;[05b8] + inc hl ;[05bb] + dec c ;[05bc] + jp nz,$03b7 ;[05bd] + and $c0 ;[05c0] + cp $40 ;[05c2] + jp z,$04b4 ;[05c4] + cp $80 ;[05c7] + jp z,$04a5 ;[05c9] + ld a,d ;[05cc] + and $c7 ;[05cd] + sub $04 ;[05cf] + jp z,$0496 ;[05d1] + dec a ;[05d4] + jp z,$0490 ;[05d5] + dec a ;[05d8] + jp z,$047c ;[05d9] + ld a,d ;[05dc] + and $c0 ;[05dd] + jp z,$044a ;[05df] + ld a,d ;[05e2] + and $07 ;[05e3] + jp z,$043f ;[05e5] + sub $02 ;[05e8] + jp z,RCV_FIRST ;[05ea] + sub $02 ;[05ed] + jp z,$0429 ;[05ef] + sub $03 ;[05f2] + jp z,$041a ;[05f4] + ld a,d ;[05f7] + and $08 ;[05f8] + jp nz,$050b ;[05fa] + ld a,d ;[05fd] + and $07 ;[05fe] diff --git a/applications/README.md b/applications/README.md index 90e4ad3..0b16d18 100644 --- a/applications/README.md +++ b/applications/README.md @@ -5,14 +5,14 @@ - CONFIG80.COM: configuration of the serial port, **disassembly in progress**; - [COPY8003.COM](COPY8003.COM.asm): disk copy utility; -- [FMT8003.COM](https://github.com/BayoDev/Sanco_8000/blob/main/CP-M/DISASSEMBLY/FMT8003_disassembly.z80): disk format utility; +- [FMT8003.COM](FMT8003.COM.asm): disk format utility; - [FUNK00.COM](FUNK00.COM.asm): keymap configuration; - [PAR8003.COM](PAR8003.COM.asm): configure diskette units; - [REV.COM](REV.COM): delete files; -- [RCX62.COM](https://github.com/BayoDev/Sanco_8000/blob/main/CP-M/DISASSEMBLY/RCX62_disassembly.z80): receive data from serial port; +- [RCX62.COM](RCX62.COM.asm): receive data from serial port; - [SG8003.COM](SG8003.COM.asm): boot sector copier, used to change the boot program - [SLF80037.COM](SLF80037.COM.asm): bootstrap application; -- [TERM80.COM](https://github.com/BayoDev/Sanco_8000/blob/main/CP-M/DISASSEMBLY/TERM80_disassembly.z80): serial terminal; +- [TERM80.COM]([TERM80.COM.asm](https://github.com/BayoDev/Sanco_8000/blob/main/CP-M/DISASSEMBLY/TERM80_disassembly.z80)): serial terminal; - [TRX62.COM](TRX62.COM): send data through serial port; ## CP/M system tools and applications diff --git a/applications/md5sum.txt b/applications/md5sum.txt index 78d2feb..a8d6aa0 100644 --- a/applications/md5sum.txt +++ b/applications/md5sum.txt @@ -5,4 +5,6 @@ b022bb2d88531e11fd4f6fc4c89f31ed build/SLF80037.relocated 2b5ea330d652f8da9cc47b3038dadbf9 build/COPY8003.COM 8924c5c5c9f22f56f06dc1f913a091a4 build/SG8003.COM -3cec9f3b89fd35aa1cd54a3997902085 build/TRX62.COM \ No newline at end of file +3cec9f3b89fd35aa1cd54a3997902085 build/TRX62.COM +5d16bdc07ffe2845aa900d0fbb5d51d9 build/RCX62.COM.asm +4288fafb9445ed7276a40b9a3c0e81b4 build/FMT8003.COM.asm \ No newline at end of file