forked from z80playground/cpm-fat
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbdos.asm
1892 lines (1657 loc) · 52.9 KB
/
bdos.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; CP/M BDOS
include "locations.asm"
include "core_jump.asm"
org BDOS_START
; BDOS size is 2.5K max. If it exceeds this there will be problems!
; See the end of the file for a Pasmo Error Check to ensure this isn't allowed to happen.
; It is most likely to happen if you enable debug mode and have lots of extra debug messages in play.
DEBUG_BDOS equ 0
OTHER_DEBUG equ 0
bdos_entry:
; The function number is passed in Register C.
; The parameter is passed in DE.
; Result returned in A or HL. Also, A=L and B=H on return for compatibility reasons.
; If function number is unknown we return A=0.
ld a, c
cp 49
jr c, BDOS_ok
cp $66 ; 102 = BDOS_Get_Date_Time
jr z, return_255_in_a
cp $69 ; BDOS function 69 - Get configuration table address
jr z, return_255_in_a ; is supported by CP/Net, so ignore it here.
call CORE_message
db 'BAD BDOS CALL: ',0
ld l, c
ld h, 0
call CORE_show_hl_as_hex
call CORE_message
db 13, 10, 0
jp $0000 ; Totally abandon anything after a bad BDOS call!
BDOS_ok:
push de
ld hl, BDOS_jump_table
ld e, c
ld d, 0
add hl, de
add hl, de
; Jump to actual BDOS entry
ld e, (hl)
inc hl
ld d, (hl)
ex de, hl ; hl now holds address of the BDOS call
pop de
call call_hl
; Now return. So anything that wants to return a value in HL should do ld a,l ld b,h first
ld l, a ; This is how the
ld h, b ; BDOS returns values.
ret ; Note that it is important to some programs that both A and B are set.
call_hl:
; This crazy-looking code does a jump to the address in hl.
; Because we called this routine, it was like we did "call hl".
push hl
ret
show_bdos_message:
call CORE_message
db 13,10,'BDOS_',0
ret
BDOS_System_Reset:
; IF DEBUG_BDOS
; call show_bdos_message
; call CORE_message
; db 'RST',13,10,0
; ENDIF
call clear_current_fcb ; Clear the Current_fcb
jp $0000
return_0_in_a:
xor a ; a = 0
ld b, a
ret
return_1_in_a:
ld a, 1
ld b, 0
ret
return_255_in_a:
ld a, 255
ld b, 0
ret
BDOS_Console_Input:
; Read a key from the keyboard.
; If there is none, wait until there is.
; Echo it to screen, and obey things like Tab, Backspace etc
call CORE_char_in
cp 0 ; Keep trying til they press something
jr z, BDOS_Console_Input
cp 32 ; Don't echo control chars
ret c
call CORE_print_a ; But do echo everything else
ret
BDOS_Console_Output:
; Prints to screen the char in e.
ld a, e
call CORE_print_a
ret
BDOS_Reader_Input:
; call show_bdos_message
; call CORE_message
; db 'Rdr_In',13,10,0
jp return_255_in_a
BDOS_Punch_Output:
; call show_bdos_message
; call CORE_message
; db 'Punch',13,10,0
jp return_255_in_a
BDOS_List_Output:
; call show_bdos_message
; call CORE_message
; db 'List',13,10,0
jp return_255_in_a
BDOS_Direct_Console_IO:
; If "E" contains FF then we are reading from the keyboard.
; If there is a key, return it in A, otherwise return 0.
; If "E" is not FF then we are writing to screen.
; Print the char directly
ld a, e
cp $FF
jr nz, BDOS_Direct_Console_IO_Write
call CORE_char_in
ld b, 1
ret
BDOS_Direct_Console_IO_Write:
call CORE_print_a
jp return_0_in_a
BDOS_Get_IO_Byte:
; call show_bdos_message
; call CORE_message
; db 'Get_IO_Byte',13,10,0
jp return_0_in_a
BDOS_Set_IO_Byte:
; call show_bdos_message
; call CORE_message
; db 'Set_IO_Byte',13,10,0
jp return_1_in_a
BDOS_Print_String:
; Print the string at "de" until we see a "$"
BDOS_Print_String1:
ld a, (de)
inc de
cp '$'
jr z, BDOS_Print_String2
call CORE_print_a
jr BDOS_Print_String1
BDOS_Print_String2
jp return_0_in_a
BDOS_Read_Console_Buffer:
; Read a line of input from the keyboard into a buffer.
; The buffer is pointed to by DE.
; The first two bytes of the buffer contain its max length and final length.
; Read in keys and put them into the buffer until the max length is reached,
; or the user presses Enter.
; Obey chars like Tab and Backspace.
ex de, hl
ld d, (hl) ; d = max buffer length
inc hl
ld (hl), 0 ; reset the "final length" byte.
ld c, l
ld b, h ; store this location
ld e, 0
inc hl
ex de, hl ; DE points to the start of the buffer spare space
push hl
push bc
pop hl ; HL points to the "final length" byte
pop bc ; B contains the max buffer length
; DE points to our target location in buffer
BDOS_Read_Console_Buffer1:
push hl
push de
push bc
call BDOS_Console_Input ; Get a char and echo it
pop bc
pop de
pop hl
cp 13 ; Done?
jr z, BDOS_Read_Console_Buffer2
cp 8 ; Ctrl-H key?
jr z, BDOS_Read_Console_Buffer_Backspace
cp 127 ; Backspace
jr z, BDOS_Read_Console_Buffer_Backspace
cp 24 ; ctrl-x -> empty line / cancel
jr z,BDOS_Read_Console_Clear_Line ;
cp 21 ; ctrl-u -> empty line / cancle
jr z,BDOS_Read_Console_Clear_Line ;
cp 3
jr z,BDOS_Read_Console_Clear_Line ; ctrl-c -> reset line
ld (de), a ; Store the char in the buffer
inc (hl) ; Increase the final-chars-count
inc de ; Move on to next place in buffer
; Decrease the max-chars counter and continue if any left
djnz BDOS_Read_Console_Buffer1
BDOS_Read_Console_Buffer2:
ld b, 0
ret
BDOS_Reboot_If_Start_of_line:
push af
ld a,(hl)
cp 0
jr z,reboot
pop af
jp BDOS_Read_Console_Clear_Line
reboot:
pop af
jp 0
BDOS_Read_Console_Clear_Line:
ld (hl),0 ; zero characters entered
inc hl
ld (hl),0 ; first character is a null
ld b,0
ret
BDOS_Read_Console_Buffer_Backspace:
ld a, (hl) ; If final-chars is zero we can't go back any more
cp 0
jr z, BDOS_Read_Console_Buffer1
ld a, ' ' ; Otherwise continue...
dec de
ld (de), a ; Clear out most recent char
dec (hl) ; Decrease final-chars-count
ld a, 8
call CORE_print_a ; Print it to go back one space
ld a, ' '
call CORE_print_a ; Cover over most recent char with space
ld a, 8
call CORE_print_a ; Print it to go back one space
inc b ; Increase max-chars-counter
jr BDOS_Read_Console_Buffer1
BDOS_Get_Console_Status:
; Is there a key available? If there is, FF, otherwise 00
jp CORE_char_available
BDOS_Return_Version_Number:
ld a, $22 ; This is CP/M v2.2
ld b, 0
ret
BDOS_Reset_Disk_System:
if DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Rst_Dsk',13,10,0
ENDIF
call clear_current_fcb ; Clear out current FCB
ld e, 0
call BDOS_Select_Disk ; Choose disk A:
ld hl, $0080
ld (dma_address), hl ; Set standard DMA location
ret
BDOS_Select_Disk:
if DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Sel_Dsk ',0
ENDIF
call CORE_close_file ; If we are changing disks, we need to close any files
; Disk is in "E". 0 = A:, 15 = P:
ld a, e
cp 16 ; Make sure desired disk is in range 0..15
jr nc, BDOS_Select_Disk_Error
ld (current_disk), a ; Store disk
; Now check that directory actually exists, and if not, make it
add a, 'A'
push af
if DEBUG_BDOS
call CORE_print_a
call CORE_newline
ENDIF
ld hl, CPM_FOLDER_NAME ; Start at /CPM
call CORE_open_file
ld hl, CPM_DISKS_NAME ; Start at /CPM/DISKS
call CORE_open_file
ld hl, filename_buffer ; Move to "A" .. "P" for required disk
pop af
ld (hl), a
inc hl
ld (hl), 0
dec hl
call CORE_open_file
cp YES_OPEN_DIR
jr z, BDOS_Select_Disk_ok
ld hl, filename_buffer ; If drive "X" is not found, create the folder for it
call CORE_create_directory
BDOS_Select_Disk_ok:
ld a, (current_user) ; If they are user 0 then all is done
cp 0
jr z, BDOS_Select_Disk_User_ok
; Now check if the User folder exists (User 1 = "1", User 15 = "F")
call CORE_convert_user_number_to_folder_name
ld hl, filename_buffer ; Move to "1" .. "F" for required user area
ld (hl), a
inc hl
ld (hl), 0
dec hl
call CORE_open_file
cp YES_OPEN_DIR
jr z, BDOS_Select_Disk_User_ok
ld hl, filename_buffer ; Create folder if not found
call CORE_create_directory
BDOS_Select_Disk_User_ok:
call clear_current_fcb ; Clear out current FCB
jp return_0_in_a
BDOS_Select_Disk_Error:
call CORE_message
db 'BDOS Error on ',0
add a, 'A'
call CORE_print_a
ld a, ':'
call CORE_print_a
call CORE_newline
jp 0
BDOS_Open_File:
; Pass in de -> FCB
; return a = 0 for success, a = 255 for error.
; The FCB that was passed in gets copied into the Current_FCB so we know which file is open.
if DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Open',13,10,0
call show_fcb
ENDIF
xor a
jp bdos_open_file_internal
bdos_open_file_internal:
; Pass in de -> FCB
; Pass in a = 0 for resetting the file pointer to 0, or a = 1 for don't-mess-with-file-pointer.
; return a = 0 for success, a = 255 for error.
; The FCB that was passed in gets copied into the Current_FCB so we know which file is open.
push af
push de
call CORE_close_file ; just in case?
pop de ; Now use FCB to open the file
pop af
cp 0
jr nz, bdos_open_file_internal1 ; If a=0 then clear the file pointer, otherwise leave as is.
ex de, hl
ld bc, 0
ld de, 0
call set_file_pointer_in_fcb
ex de, hl
bdos_open_file_internal1:
;call show_fcb
push de
call copy_fcb_to_filename_buffer
;call show_filename_buffer
call open_cpm_disk_directory
ld hl, filename_buffer+2 ; Specify search pattern "*"
call CORE_open_file
jr z, open_file_success
pop de
call clear_current_fcb ; No file open so clear out the Current FCB
jp return_255_in_a ; error
open_file_success:
pop de
call copy_fcb_to_current_fcb ; File is now open, so copy FCB to Current FCB
jp return_0_in_a
open_cpm_disk_directory:
; This opens the directory for a file on a CP/M disk, such as /CPM/DISKS/A or /CPM/DISKS/B/1
ld hl, CPM_FOLDER_NAME ; Start at "/CPM"
call CORE_open_file
ld hl, CPM_DISKS_NAME ; Then "DISKS"
call CORE_open_file
; Now drive letter
ld hl, filename_buffer
ld a, (hl)
ld hl, DRIVE_NAME ; Move to "A" .. "P" for required disk
ld (hl), a
inc hl
ld (hl), 0
dec hl
call CORE_open_file
; Now user number (if greater than 0)
ld a, (current_user)
cp 0
ret z
call CORE_convert_user_number_to_folder_name
ld hl, DRIVE_NAME ; Move to "1" .. "F" for required user
ld (hl), a
inc hl
ld (hl), 0
dec hl
call CORE_open_file
ret
BDOS_Close_File:
; Pass in de -> FCB
; return 0 for success, 255 for fail
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Close',13,10,0
ENDIF
call CORE_close_file
call clear_current_fcb ; Clear out current FCB
jp return_0_in_a
BDOS_Search_for_First:
; Input is DE -> FCB
; Output is $FF if nothing found, otherwise 0 in A and the directory entry will have
; been copied into the current DMA location.
; The FCB contains the drive and file name.
; The drive can be 0 to 15 for A to P, or '?' to mean current drive.
; The filename and extension can be letters, or "?" or "*" for wildcards.
; This leaves the disk in such a position that "search_for_next" cen get the next entry.
; What we do is:
; - Open the correct folder, e.g. /CPM/DISKS/A/user
; - Read in a filename and put it into the DMA area.
; - Check if it matches. If not, try the next.
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Srch_Fst',13,10,0
call show_fcb
ENDIF
call copy_fcb_to_filename_buffer_preserving_spaces
ld de, (dma_address)
ld a, (current_user)
call CORE_dir ; returns 0 = success, 255 = fail
cp 0
jr z, search_first_found
IF DEBUG_BDOS
call CORE_message
db 'DIR NONE',13,10,0
ENDIF
jp return_255_in_a ; Found nothing
search_first_found:
IF DEBUG_BDOS
call CORE_message
db 'DIR:',13,10,0
ld de, (dma_address)
call show_fcb
ENDIF
jp return_0_in_a ; Success!
BDOS_Search_for_Next:
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Srch_Nx',13,10,0
ENDIF
ld de, (dma_address)
ld a, (current_user)
call CORE_dir_next ; returns 0 = success, 255 = fail
cp 0
jr z, search_next_found
IF DEBUG_BDOS
call CORE_message
db 'NONE!',13,10,0
ENDIF
jp return_255_in_a ; Found nothing
search_next_found:
IF DEBUG_BDOS
call CORE_message
db 'NEXT ret:',13,10,0
ld de, (dma_address)
call show_fcb
ENDIF
jp return_0_in_a ; Success!
BDOS_Delete_File:
; Delete File passes in DE->FCB
; Returns a = 0 for success and a = 255 for failure.
; I think that we return 0 if we delete a file, and 255 if we don't, even though
; that is not exactly an error condition.
IF OTHER_DEBUG
call show_bdos_message
call CORE_message
db 'Del',13,10,0
call show_fcb
ENDIF
; We enter with DE pointing to a FCB, such as "file.xyz" or "*.txt".
; We use this to run a DIR-search-first, returning a result in A (0=good) and
; storing its resulting FCB in a temporary FCB.
; If no file was found then we are done.
; If a file was found then we need to delete that file, and loop back to the start.
ld a, 255
ld (delete_flag), a ; Store the result
; Store drive letter of requested file to delete
ld a, (de)
ld (store_source), a
; Do a DIR-search-first, using the fcb passed in DE
push de
call clear_current_fcb ; Clear out current FCB
pop de
BDOS_Delete_File_loop:
push de
call copy_fcb_to_filename_buffer_preserving_spaces
ld de, temp_fcb
ld a, (current_user)
call CORE_dir ; returns 0 = success, 255 = fail
cp 255
jr z, BDOS_Delete_File_done
; File found, so delete it
xor a
ld (delete_flag), a ; Store a success reult
; restore the drive letter saved from the originally requested file
ld a, (store_source)
ld (temp_fcb), a
IF OTHER_DEBUG
call CORE_message
db 'DELETING ',13,10,0
ld de, temp_fcb
call show_fcb
ENDIF
ld de, temp_fcb
call copy_fcb_to_filename_buffer
call CORE_close_file ; just in case there is an open one.
call clear_current_fcb
call open_cpm_disk_directory
ld hl, filename_buffer+2 ; Specify filename
call CORE_open_file
jr nz, delete_error ; Don't delete if not found
call CORE_erase_file
pop de ; Get original FCB back
jr BDOS_Delete_File_loop
BDOS_Delete_File_done:
pop de
IF OTHER_DEBUG
call CORE_message
db 'DEL done',13,10,0
ENDIF
ld a, (delete_flag)
ld b, 0
ret
delete_error:
pop de
jp return_255_in_a
BDOS_Read_Sequential:
; Pass in de -> FCB
; Return a = 0 on success, or a != 0 on error
; We need to read 128 bytes from the current position of the file referenced in FCB
; to DMA address.
; If there are less than 128 bytes, made sure the rest is padded with nulls.
; Start by checking that the FCB equals the Current FCB.
; If not, close the current file and open the new one, jumping to the right place.
; If so just proceed.
; Then increase the pointer in the FCB and copy it to Current_FCB.
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Rd_Seq',13,10,0
call show_fcb
ENDIF
push de
call disk_activity_start
call compare_current_fcb
jr z, BDOS_Read_Sequential1
; Need to close existing file and open the new one.
ld a, 1 ; Open new file but don't update file pointer
call bdos_open_file_internal
pop de
push de
; Now jump to the right place in the file
call get_file_pointer_from_fcb ; bcde = file pointer
call multiply_bcde_by_128 ; bcde = byte location in file
call CORE_move_to_file_pointer ; move to that location
cp USB_INT_SUCCESS
jr nz, read_from_file_fail
BDOS_Read_Sequential1:
ld de, (dma_address)
call CORE_read_from_file
jr nz, read_from_file_fail ; ADDED IN, BUT MAKES SENSE???
pop de ; Get the FCB location back
push de
call get_file_pointer_from_fcb ; bcde = file pointer
call increase_bcde
pop hl
call set_file_pointer_in_fcb
ex de, hl
call copy_fcb_to_current_fcb ; Make a note of the state of the currently open file
call CORE_disk_off
jp return_0_in_a ; Success
read_from_file_fail:
pop de
call CORE_disk_off
ld a, 1 ; 1 = seek to unwritten extent
ld b, 0
ret
BDOS_Write_Sequential:
; Pass in de -> FCB
; Return a = 0 on success, or a = 255 on error
; We need to write 128 bytes from the current DMA address to the
; current position of the file referenced in FCB.
; Start by checking that the FCB equals the Current FCB.
; If not, close the current file and open the new one, jumping to the right place.
; If so just proceed.
; Then increase the pointer in the FCB and copy it to Current_FCB.
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Wr_Seq',13,10,0
call show_fcb
ENDIF
push de
call disk_activity_start
dont_turn_on:
call compare_current_fcb
jr z, BDOS_Write_Sequential1
; Need to close existing file and open the new one.
ld a, 1 ; Open new file but don't update file pointer
call bdos_open_file_internal
pop de
push de
; Now jump to the right place in the file
call get_file_pointer_from_fcb ; bcde = file pointer
call multiply_bcde_by_128 ; bcde = byte location in file
call CORE_move_to_file_pointer ; move to that location
cp USB_INT_SUCCESS
jr nz, BDOS_Write_Sequential_fail
BDOS_Write_Sequential1:
ld de, (dma_address)
call CORE_write_to_file
call CORE_disk_off
pop de ; Get the FCB location back
push de
call get_file_pointer_from_fcb ; bcde = file pointer
call increase_bcde
pop hl
call set_file_pointer_in_fcb
ex de, hl
call copy_fcb_to_current_fcb ; Make a note of the state of the currently open file
jp return_0_in_a
BDOS_Write_Sequential_fail:
pop de
call CORE_message
db 'BDOS write error!',13,10,0
call CORE_disk_off
jp return_255_in_a
BDOS_Make_File:
; Make File passes in DE->FCB
; Returns a = 0 for success and a = 255 for failure
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Mk_File',13,10,0
call show_fcb
ENDIF
push de
call CORE_close_file ; just in case another file is open
pop de
push de
call copy_fcb_to_filename_buffer
call CORE_disk_on
call CORE_connect_to_disk
call CORE_mount_disk
call open_cpm_disk_directory
ld de, filename_buffer+2 ; Specify filename
call CORE_create_file
jr z, make_file_success
call CORE_disk_off
pop de
call clear_current_fcb ; Clear out current FCB because of fail.
jp return_255_in_a ; error
make_file_success:
call CORE_disk_off
pop de
call copy_fcb_to_current_fcb ; This is now the currently open file
jp return_0_in_a
BDOS_Rename_File:
; DE points to a FCB with the
; SOURCE filename at FCB+0 and
; TARGET filename at FCB+16.
; The disk drive must be the same in both names, or else error.
; Check if the target file already exists. If so return with error.
; Success a = 0
; Error a = 255
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Ren',13,10,0
ENDIF
ld (store_source), de ; Store source FCB pointer for now
push de
call CORE_close_file ; just in case there is an open one.
pop de
IF DEBUG_BDOS
; show source FCB
call CORE_message
db 'Src:',13,10,0
call show_fcb
call CORE_message
db 'Tgt:',13,10,0
ENDIF
ld hl, 16
add hl, de
ld (store_target), hl ; And store the target FCB for now
ex de, hl ; target is now in de
IF DEBUG_BDOS
; Show target FCB
call show_fcb
ENDIF
; Check if target drive is "default", if so, copy from source.
ld hl, (store_target) ; retrieve pointer to target file
ld a, (hl) ; Target file drive letter
cp 0 ; Is the target of the default drive?
jr nz, BDOS_Rename_target_not_default ; This indicates it should be the same as the source
ld de, (store_source)
ld a, (de)
ld (hl), a ; Copy drive from source to target
BDOS_Rename_target_not_default:
; Check if both drives are the same. If not return error.
ld hl, (store_target)
ld a, (hl) ; Get target drive
ld hl, (store_source) ; retrieve source fcb
cp (hl) ; Are drive letters the same?
jr nz, BDOS_Rename_File_different_drives
; Try opening target file. If we can then return an error.
ld de, (store_target)
call copy_fcb_to_filename_buffer
call open_cpm_disk_directory
ld hl, filename_buffer+2 ; Specify filename
call CORE_open_file
jr z, BDOS_Rename_File_exists
BDOS_Rename_File_same_drives:
; Open the source file.
call CORE_close_file
ld de, (store_source)
call copy_fcb_to_filename_buffer
call open_cpm_disk_directory
ld hl, filename_buffer+2 ; Specify source filename
call CORE_open_file
jp nz, BDOS_Rename_File_no_source
; Read in the P_FAT_DIR_INFO
call CORE_dir_info_read
jr nz, BDOS_Rename_File_no_source
; Update the name of the target file by copying the name from target to source
ld hl, (store_target)
inc hl
ld de, disk_buffer
ld bc, 11
ldir
; Write it back again.
call CORE_dir_info_write
; Close the file.
call CORE_close_file
call clear_current_fcb ; Clear out current FCB
jp return_0_in_a ; success
BDOS_Rename_File_exists:
;call CORE_message
;db '[EXISTS]',13,10,0
jp return_255_in_a
BDOS_Rename_File_different_drives:
;call CORE_message
;db '[DIFF]',13,10,0
jp return_255_in_a
BDOS_Rename_File_no_source:
;call CORE_message
;db '[NONE]',13,10,0
jp return_255_in_a
BDOS_Return_Login_Vector:
;call show_bdos_message
;call CORE_message
;db 'Ret_Log_Vec',13,10,0
ld hl, $FFFF ; All drives are always logged in
ld a, l
ld b, h
ret
BDOS_Return_Current_Disk:
;call show_bdos_message
;call CORE_message
;db 'Ret_Curr_Disk',13,10,0
; The value is 0 = A .. 15 = P
ld a, (current_disk)
and %00001111 ; Make sure it is 0-15
;push af
;add a, 'A'
;call CORE_print_a
;call newline
;pop af
ld b, 0
ret
BDOS_Set_DMA_Address:
; Pass in de -> DMA Address
ld (dma_address), de
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Set_DMA ',0
ex de, hl
call CORE_show_hl_as_hex
call CORE_newline
ENDIF
jp return_0_in_a
BDOS_Get_Addr_Alloc:
; IF DEBUG_BDOS
; call show_bdos_message
; call CORE_message
; db 'Get_DSKAL',13,10,0
; ENDIF
ld hl, DISKALLOC
ld a, l
ld b, h
ret
BDOS_Write_Protect_Disk:
;call show_bdos_message
;call CORE_message
;db 'Wr_Prot_Disk',13,10,0
jp return_1_in_a
BDOS_Get_RO_Vector:
;call show_bdos_message
;call CORE_message
;db 'Get_RO_Vect',13,10,0
jp return_1_in_a
BDOS_Set_File_Attributes:
;call show_bdos_message
;call CORE_message
;db 'Set_File_Attr',13,10,0
jp return_1_in_a
BDOS_Get_Addr_Disk_Parms:
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Get_DPB ',0
ENDIF
; Returns address in HL
ld hl, dpblk
ld a, l
ld b, h
ret
BDOS_Set_Get_User_Code:
;call show_bdos_message
;call CORE_message
;db 'Set_Get_User',13,10,0
; The user to set is passed in E. This is a value from 0 to 15.
; If the value is 255 then we are asking for the current user to be returned in a.
ld a, e
cp 255
jr z, get_user_code
set_user_code:
ld a, e
and %00001111 ; Make sure it is 0-15
ld (current_user), a ; Store new value
ld a, (current_disk)
ld e, a
call BDOS_Select_Disk ; Change to the appropriate folder
ret
get_user_code:
ld a, (current_user)
ld b, 0
ret
BDOS_Read_Random:
IF DEBUG_BDOS
call show_bdos_message
call CORE_message
db 'Rd_Rnd',13,10,0
call show_fcb
ENDIF
BDOS_Read_Random1:
push de ; store FCB for now
call disk_activity_start
call get_random_pointer_from_fcb ; random is in hl
call convert_random_pointer_to_normal_pointer ; Normal pointer is in bcde
pop hl ; hl -> fcb
push hl
call set_file_pointer_in_fcb ; FCB is now up-to-date
pop de ; de -> FCB
push de
; Need to close any existing open file and open the new one.
ld a, 1 ; Open new file but don't update file pointer
call bdos_open_file_internal
pop de
; Now jump to the right place in the file
call get_file_pointer_from_fcb ; bcde = file pointer
call multiply_bcde_by_128 ; bcde = byte location in file
call CORE_move_to_file_pointer ; move to that location
ld de, (dma_address)
call CORE_read_from_file
jr nz, BDOS_Read_Random2 ; If fail to read, return error code
call CORE_close_file