OK240.2-Firmware/CPM_v2.2_r8_bc0695e4/bios.asm

833 lines
24 KiB
NASM

; =======================================================
; Ocean-240.2
;
; CP/M BIOS
;
; Disassembled by Romych 2025-09-09
; =======================================================
INCLUDE "equates.inc"
INCLUDE "ram.inc"
INCLUDE "mon_entries.inc"
DEFINE CHECK_INTEGRITY
IFNDEF BUILD_ROM
OUTPUT bios.bin
ENDIF
MODULE BIOS
ORG 0xD600
; -------------------------------------------------------
; BIOS JUMP TABLE
; -------------------------------------------------------
boot_f:
JP bios_boot
wboot_f:
JP bios_wboot
; -------------------------------------------------------
; console status to reg-a
; -------------------------------------------------------
const_f:
JP MON.non_con_status
; -------------------------------------------------------
; console character to reg-a
; -------------------------------------------------------
conin_f:
JP MON.mon_con_in
; -------------------------------------------------------
; console character from c to console out
; -------------------------------------------------------
conout_f:
JP MON.mon_con_out
; -------------------------------------------------------
; list device out
; -------------------------------------------------------
list_f:
JP MON.mon_char_print
; -------------------------------------------------------
; punch device out
; -------------------------------------------------------
punch_f:
JP MON.mon_serial_out
; -------------------------------------------------------
; reader character in to reg-a
; -------------------------------------------------------
reader_f:
JP MON.mon_serial_in
; -------------------------------------------------------
; move to home position, treat as track 00 seek
; -------------------------------------------------------
home_f:
JP home
; -------------------------------------------------------
; select disk given by register c
; -------------------------------------------------------
seldsk_f:
JP sel_disk
settrk_f:
JP set_trk
setsec_f:
JP set_sec
; -------------------------------------------------------
; Set DMA address from BC
; -------------------------------------------------------
setdma_f:
JP set_dma
read_f:
JP read
write_f:
JP write
listst_f:
JP list_st
sectran_f:
JP sec_tran
; -------------------------------------------------------
; Reserved
; -------------------------------------------------------
JP warm_boot
JP warm_boot
; -------------------------------------------------------
; Tape read
; -------------------------------------------------------
tape_read_f:
JP MON.mon_tape_read
; -------------------------------------------------------
; Tape write
; -------------------------------------------------------
tape_write_f:
JP MON.mon_tape_write
; -------------------------------------------------------
; Tape wait block
; -------------------------------------------------------
tape_wait_f:
JP MON.mon_tape_wait
JP warm_boot ; r8
disk_a_size DW 192 ; 192k disk A size
disk_b_size DW 720 ; 720 disk B size
disk_c_size DW 720 ; 720 disk C size
disk_b_tracks DB 80
disk_c_tracks DB 80
; -------------------------------------------------------
; cold start
; -------------------------------------------------------
bios_boot:
LD HL, (bdos_ent_addr) ; 0xba06
LD DE, 0x10000-CCP_RAM.bdos_enter_jump ; 0x45fa
ADD HL, DE ; 0xba06+0x45fa=10000
LD A, H
OR L
JP Z, bios_signon
; >> r8
LD HL, (bios_var0) ; if bios_var0 = 0xaaaa (initialized)
LD DE, 0x5556
ADD HL, DE ; 0xaaaa+0x5556=0x10000 if initialized
LD A, H
OR L
JP Z, bios_signon ; if initialized, go to logon, skip init
; <<
; Init DMA buffer
LD HL, dma_buffer ; 0x8000
LD B, DMA_BUFF_SIZE ; 0x80
.init_dma_buff:
LD (HL), FILE_DELETED ; 0xE5
INC HL
DEC B
JP NZ, .init_dma_buff
; Init RAM disk
LD HL, dma_buffer
LD DE, 0x0000
LD B, 8
.init_ram_dsk:
PUSH BC
CALL MON.ram_disk_write
POP BC
INC DE
DEC B
JP NZ, .init_ram_dsk
; Init user to 0 and drive to 0
XOR A
LD (cur_user_drv), A
; init bios variables
CALL bios_init_ilv ; r8
bios_signon:
LD SP, bios_stack
; Print CP/M hello message
LD HL, msg_hello
CALL print_strz
JP bios_wboot
;bios_wboot:
; LD SP, bios_stack
; r8 >>
bios_init_ilv:
LD HL, bios_var0
LD DE, bios_ini_vals
LD C, 13
CALL mov_dlhe_c
LD A, (disk_c_tracks) ; 0x50
LD (disk_c_tracks), A
RET
; <<
; -------------------------------------------------------
; BIOS Warm start entry
; -------------------------------------------------------
bios_wboot: ; r8
LD HL, (bios_var0)
LD DE, 0x5556 ; 0xaaaa + 0x5556 = 0x10000
ADD HL, DE
LD A, H
OR L
CALL NZ, bios_init_ilv ; init if not initialized before
LD SP, bios_stack
; Move CPP from 0xC000 to 0xB200
LD HL, CCP_DST_ADDR
LD DE, CCP_SRC_ADDR
LD BC, CCP_SIZE
.move_ccp:
LD A, (DE)
LD (HL), A
INC DE
INC HL
DEC BC
LD A, B
OR C
JP NZ, .move_ccp
; Init variables with zeroes
LD HL, CPM_VARS.cpm_vars_start
LD BC, CPM_VARS.ccp_vars_size ; 213
.clr_cpm_vars:
LD (HL), 0x0
INC HL
DEC BC
LD A, B
OR C
JP NZ, .clr_cpm_vars
LD A, FILE_DELETED
LD (CPM_VARS.bdos_efcb), A ; mark empty FCB
LD A, low dma_buffer ; 0x80
LD (CPM_VARS.bdos_dmaad), A ; 0x0080
; Move DPH + DPB to RAM
LD HL, CPM_VARS.DPH_RAM
LD DE, dph_disk_a
LD BC, DPB_END-dph_disk_a ; 0x39 -> 57d
.move_dph:
LD A, (DE)
LD (HL), A
INC HL
INC DE
DEC BC
LD A, B
OR C
JP NZ, .move_dph
LD BC, dma_buffer ; DMA default buffer addr
CALL setdma_f
; Setup JP to Warm boot after CPU reset
LD A, JP_OPCODE
LD (warm_boot), A
LD HL, wboot_f
LD (warm_boot_addr), HL
; Setup JP to BDOS entrance
LD (jp_bdos_enter), A
LD HL, CCP_RAM.bdos_enter_jump
LD (bdos_ent_addr), HL
; Disk A
LD HL, CPM_VARS.DPB_A_RAM
LD C, 0xf
LD DE, dpb_ram
LD A, (disk_a_size+1)
OR A
JP Z, .drv_a_192
LD DE, dpb_empty
.drv_a_192:
CALL mov_dlhe_c
; Disk B
LD HL, CPM_VARS.DPB_B_RAM
LD C, 0xf
LD DE, dpb_flop_360k
LD A, (disk_b_size+1)
CP 0x1
JP Z, .drv_b_360
LD DE, dpb_flop_720k
.drv_b_360:
CALL mov_dlhe_c
; Disk C
LD HL, CPM_VARS.DPB_C_RAM
LD C, 0xf
LD A, (disk_c_size+1)
CP 0x2 ; 720?
JP Z, .drv_c_720
LD DE, dpb_flop_360k
; bios_var3 != 0 -> move DPB 360k
LD A, (disk_sw_trk)
OR A
JP NZ, .drv_c_mov
; bios_var3 == 0 -> move DPB 720k
LD DE, dpb_flop_720k
JP .drv_c_mov
.drv_c_720:
LD DE, dpb_flop_720k
; bios_var3 != 0 -> move DPB 720k
LD A, (disk_sw_trk)
OR A
JP NZ, .drv_c_mov
; bios_var3 == 1 -> move DPB 360k
LD DE, dpb_flop_360k
.drv_c_mov:
CALL mov_dlhe_c
XOR A
LD (CPM_VARS.slicer_has_data),A
LD (CPM_VARS.slicer_uninited_count),A
LD A,(cur_user_drv)
LD C,A
; go to CCP
JP CCP_DST_ADDR
; -------------------------------------------------------
; Move C bytes from [DE] to [HL]
; -------------------------------------------------------
mov_dlhe_c:
LD A,(DE) ; [DE]->[HL]
LD (HL),A
INC HL
INC DE
DEC C
JP NZ, mov_dlhe_c
RET
list_st:
XOR A
RET
; -------------------------------------------------------
; Select disk
; Inp: C - disk,
; E - active drive flag
; Out: HL -> DPH
; -------------------------------------------------------
sel_disk:
LD HL, 0x00
LD A, C
CP CTRL_C
RET NC
LD (CPM_VARS.cur_disk), A
OR A
JP Z, .get_dph_addr ; skip next for disk 0 - RAM disk
LD A, E ; selected disk map
AND 0x1 ; bit 0 is set if disk already selected
JP NZ, .get_dph_addr
; Reset disk
LD (CPM_VARS.slicer_has_data), A
LD (CPM_VARS.slicer_uninited_count), A
; calc DPH address of new drive
.get_dph_addr:
LD L, C
LD H, 0x0
ADD HL, HL ; *2
ADD HL, HL ; *4
ADD HL, HL ; *8
ADD HL, HL ; *16 (size of DBH)
LD DE, CPM_VARS.DPH_RAM
ADD HL, DE
RET
; -------------------------------------------------------
; move to track 00
; -------------------------------------------------------
home:
LD A, (CPM_VARS.cur_disk)
OR A
JP Z, .is_default
LD A, (CPM_VARS.slicer_need_save)
OR A
JP NZ, .is_default
LD (CPM_VARS.slicer_has_data), A ; set to 0, no data
.is_default:
LD C, 0 ; set track to 0
; -------------------------------------------------------
; set track address (0..76) for subsequent read/write
; -------------------------------------------------------
set_trk:
LD HL, CPM_VARS.curr_track
LD (HL), C
RET
; -------------------------------------------------------
; set sector address (1,..., 26) for subsequent read/write
; -------------------------------------------------------
set_sec:
LD HL, CPM_VARS.curr_sec
LD (HL), C
RET
; -------------------------------------------------------
; set subsequent dma address (initially 80h)
; -------------------------------------------------------
set_dma:
LD L, C
LD H, B
LD (CPM_VARS.dma_addr), HL
RET
sec_tran:
LD L, C
LD H, B
RET
; -------------------------------------------------------
; read track/sector to preset dma address
; -------------------------------------------------------
read:
LD A, (CPM_VARS.cur_disk)
OR A
JP NZ, read_phys ; for physical disk use special routine
CALL ram_disk_calc_addr
CALL MON.ram_disk_read
XOR A
RET
; -------------------------------------------------------
; write track/sector from preset dma address
; -------------------------------------------------------
write:
LD A, (CPM_VARS.cur_disk)
OR A
JP NZ,write_phys
CALL ram_disk_calc_addr
CALL MON.ram_disk_write
XOR A
RET
; -------------------------------------------------------
; Calculate address for current sector and track
; -------------------------------------------------------
ram_disk_calc_addr:
LD HL, CPM_VARS.curr_track
; HL = cur_track * 16
LD L, (HL)
LD H, 0x0
ADD HL, HL
ADD HL, HL
ADD HL, HL
ADD HL, HL
; DE = HL + cur_sec
EX DE, HL
LD HL, CPM_VARS.curr_sec
LD L, (HL)
LD H, 0x0
ADD HL, DE
EX DE, HL
; store address
LD HL, (CPM_VARS.dma_addr)
RET
read_phys:
CALL read_phys_op
RET
write_phys:
CALL write_phys_op
RET
read_phys_op:
XOR A
; reset counter
LD (CPM_VARS.slicer_uninited_count), A
LD A, 0x1
LD (CPM_VARS.tmp_slicer_operation), A ; 0 - write; 1 - read
LD (CPM_VARS.tmp_slicer_can_read), A ; enable read fron disk
LD A, 0x2
LD (CPM_VARS.tmp_slicer_flush), A ; disable flush data to disk
JP base_read_write
write_phys_op:
XOR A
LD (CPM_VARS.tmp_slicer_operation), A
LD A, C
LD (CPM_VARS.tmp_slicer_flush), A
CP 0x2
JP NZ, .mode_ne_2
LD A, 0x10 ; 2048/128
LD (CPM_VARS.slicer_uninited_count), A
LD A, (CPM_VARS.cur_disk)
LD (CPM_VARS.slicer_uninited_disk), A
LD A, (CPM_VARS.curr_track)
LD (CPM_VARS.slicer_uninited_track), A
LD A, (CPM_VARS.curr_sec)
LD (CPM_VARS.slicer_uninited_sector_128), A
.mode_ne_2:
LD A, (CPM_VARS.slicer_uninited_count)
OR A
JP Z, slicer_read_write
DEC A
LD (CPM_VARS.slicer_uninited_count), A
LD A, (CPM_VARS.cur_disk)
LD HL, CPM_VARS.slicer_uninited_disk
CP (HL)
JP NZ, slicer_read_write
LD A, (CPM_VARS.curr_track)
LD HL, CPM_VARS.slicer_uninited_track
CP (HL)
JP NZ, slicer_read_write
LD A, (CPM_VARS.curr_sec)
LD HL, CPM_VARS.slicer_uninited_sector_128
CP (HL)
JP NZ, slicer_read_write
INC (HL)
LD A, (HL)
CP 36 ; Sectors per track
JP C, .no_inc_track
LD (HL), 0x0
LD A, (CPM_VARS.slicer_uninited_track)
INC A
LD (CPM_VARS.slicer_uninited_track), A
.no_inc_track:
XOR A
LD (CPM_VARS.tmp_slicer_can_read), A
JP base_read_write
; --------------------------------------------------
slicer_read_write:
XOR A
LD (CPM_VARS.slicer_uninited_count), A
INC A
LD (CPM_VARS.tmp_slicer_can_read), A
; --------------------------------------------------
base_read_write:
XOR A
LD (CPM_VARS.tmp_slicer_result), A
LD A, (CPM_VARS.curr_sec)
OR A
RRA
OR A
RRA
LD (CPM_VARS.tmp_slicer_real_sector), A
LD HL, CPM_VARS.slicer_has_data
LD A, (HL)
LD (HL), 0x1
OR A
JP Z, .no_data
LD A, (CPM_VARS.cur_disk)
LD HL, CPM_VARS.slicer_disk
CP (HL)
JP NZ, .pos_diff
LD A, (CPM_VARS.curr_track)
LD HL, CPM_VARS.slicer_track
CP (HL)
JP NZ, .pos_diff
LD A, (CPM_VARS.tmp_slicer_real_sector)
LD HL, CPM_VARS.slicer_real_sector
CP (HL)
JP Z,calc_sec_addr_in_bfr
.pos_diff:
LD A, (CPM_VARS.slicer_need_save)
OR A
CALL NZ, slicer_save_buffer ; save buffer if needed
.no_data:
LD A, (CPM_VARS.cur_disk)
LD (CPM_VARS.slicer_disk), A
LD A, (CPM_VARS.curr_track)
LD (CPM_VARS.slicer_track), A
LD A, (CPM_VARS.tmp_slicer_real_sector)
LD (CPM_VARS.slicer_real_sector), A
LD A, (CPM_VARS.tmp_slicer_can_read)
OR A
CALL NZ,slicer_read_buffer
XOR A
LD (CPM_VARS.slicer_need_save), A
; --------------------------------------------------
calc_sec_addr_in_bfr:
LD A, (CPM_VARS.curr_sec)
AND 0x3
LD L, A
LD H, 0
ADD HL, HL
ADD HL, HL
ADD HL, HL
ADD HL, HL
ADD HL, HL
ADD HL, HL
ADD HL, HL ; *128
LD DE, CPM_VARS.slicer_buffer
ADD HL, DE
EX DE, HL
LD HL, (CPM_VARS.dma_addr)
LD C, 0x80
LD A, (CPM_VARS.tmp_slicer_operation)
OR A
JP NZ, .no_save
LD A, 0x1
LD (CPM_VARS.slicer_need_save), A
EX DE, HL
.no_save:
LD A, (DE)
INC DE
LD (HL), A
INC HL
DEC C
JP NZ, .no_save
LD A, (CPM_VARS.tmp_slicer_flush)
CP 0x1
LD A, (CPM_VARS.tmp_slicer_result)
RET NZ
OR A
RET NZ
XOR A
LD (CPM_VARS.slicer_need_save), A
CALL slicer_save_buffer
LD A, (CPM_VARS.tmp_slicer_result)
RET
; --------------------------------------------------
slicer_save_buffer:
CALL slicer_get_floppy_args
LD C, 0xA6 ; VG93 CMD
CALL MON.write_floppy
LD (CPM_VARS.tmp_slicer_result), A
RET
; --------------------------------------------------
slicer_read_buffer:
CALL slicer_get_floppy_args
LD C, 0x86 ; VG93 CMD
CALL MON.read_floppy
LD (CPM_VARS.tmp_slicer_result), A
RET
; --------------------------------------------------
slicer_get_floppy_args:
LD HL, CPM_VARS.tmp_buff9
LD A, (CPM_VARS.slicer_disk)
DEC A
JP Z, .non_interleave
LD HL, interleave_0
.non_interleave:
LD A, (CPM_VARS.slicer_real_sector)
ADD A, L
LD L, A
LD E, (HL)
LD A, (CPM_VARS.slicer_track)
LD D, A
LD HL, CPM_VARS.slicer_buffer
LD A, (CPM_VARS.slicer_disk)
RET
; -------------------------------------------------------
; Print zerro ended string
; Inp: HL -> string
; -------------------------------------------------------
print_strz:
LD A, (HL)
OR A
RET Z
LD C, A
PUSH HL
CALL conout_f
POP HL
INC HL
JP print_strz
msg_hello:
DB ASCII_ESC, "6", "0" ; 40x25 cursor on
DB ASCII_ESC, "8", "3" ; set palette
DB ASCII_ESC, "5", 33, 37 ; set cursor r,c
DB ASCII_ESC, "4", "1" ; set color
DB ASCII_ESC, "1", 22, 226, 226, 252, 1 ; draw fill rect x1,y1,x2,y2,m
DB ASCII_ESC, "4", "0" ; set color
DB ASCII_ESC, "1", 30, 230, 219, 248, 1 ; draw fill rect x1,y1,x2,y2,m
DB ASCII_ESC, "4", "3" ; set color
DB "OKEAH-240 CP/M (V2.2) REL.8'\r\n\n"
DB ASCII_ESC, "4", "2", 0 ; set color
; --------------------------------------------------
; Disk parameters blocks in ROM (DPBs)
; Tables of memory that describe the characteristics
; of discs on our system. There is one DPB for each
; disc type
; ----------------------------------------
; Block size | No of sectors | BSH | BLM |
; ----------------------------------------
; 1K | 8 | 3 | 7 |
; 2K | 16 | 4 | 15 |
; 4K | 32 | 5 | 31 |
; 8K | 64 | 6 | 63 |
; 16K | 128 | 7 | 127 |
; ----------------------------------------
; -------------------------------------
; Block size| Extent mask (EXM) |
; | Small disk | Large disk |
; -------------------------------------
; 2K | 1 | 0 |
; 4K | 3 | 1 |
; 8K | 7 | 3 |
; 16K | 15 | 7 |
; -------------------------------------
; CKS - number of dir sectors to check before write, 0 for HDD
; For RAM-Disk 192k
dpb_ram:
DW 16 ; SPT Sector (128b) per track (16d)
DB 3 ; BSH 1k
DB 7 ; BLM 1k; Allocation block size = (BLM + 1) * 128 = 1k
DB 0 ; EXM extent mask
DW 191 ; DSM Disk size blocks - 1
DW 31 ; DRM Dir elements - 1
DB 10000000b ; AL0 Dir map byte 1
DB 00000000b ; AL1 Dir map byte 2
DW 0x0008 ; CKS checksum vector size (8 sectors=1k)
DW 0x0000 ; OFF (tracks reserved for system)
dpb_empty:
DS 15, 0xff
; For FLOPPY 720k
dpb_flop_720k:
DW 36 ; SPT Sector (128b) per track 36 * 128 = 18KB
DB 4 ; BSH 2k
DB 15 ; BLM 2k; Allocation block size = (BLM + 1) * 128 = 2k
DB 0 ; EXM extent mask
DW 359 ; DSM Disk size blocks - 1 (359d)
DW 127 ; DRM Directory entries - 1 (127d)
DB 11000000b ; AL0 Dir map byte 1 (2 dir blk)
DB 00000000b ; AL1 Dir map byte 2
DW 32 ; CKS checksum vector size (32 sectors = 2k)
DW 0x0000 ; OFF (No of tracks reserved for system)
; For FLOPPY 360k
dpb_flop_360k:
DW 36 ; SPT Sector (128b) per track 36 * 128 = 18KB
DB 4 ; BSH 2k
DB 15 ; BLM 2k; Allocation block size = (BLM + 1) * 128 = 2k
DB 1 ; EXM extent mask
DW 179 ; DSM Disk size blocks - 1 (179d)
DW 127 ; DRM Directory entries - 1 (127d)
DB 11000000b ; AL0 Dir map byte 1 (2 dir blk)
DB 00000000b ; AL1 Dir map byte 2
DW 32 ; CKS checksum vector size (32 sectors = 2k)
DW 0x0000 ; OFF (No of tracks reserved for system)
bios_ini_vals:
DB 0xaa, 0xaa, 0, 0xff, 1, 8, 6, 4, 2, 9, 7, 5, 3
; --------------------------------------------------
; Disk parameters headers in ROM
; --------------------------------------------------
; Disk A RAM
dph_disk_a:
DW 0 ; Sector translate table pointer
DW 0, 0, 0 ; Scratchpad area
DW CPM_VARS.dir_buffer ; Directory buffer pointer
DW CPM_VARS.DPB_A_RAM ; DPB Pointer
DW CPM_VARS.CHK_VEC_A ; Check Vector pointer
DW CPM_VARS.AL_MAP_A ; Allocation map pointer
; Disk B Floppy
dph_disk_b:
DW 0 ; Sector translate table pointer
DW 0, 0, 0 ; Scratchpad area
DW CPM_VARS.dir_buffer ; Directory buffer pointer
DW CPM_VARS.DPB_B_RAM ; DPB Pointer
DW CPM_VARS.CHK_VEC_B ; Check Vector pointer
DW CPM_VARS.AL_MAP_B ; Allocation map pointer
; Disk C Floppy
dph_disk_c:
DW 0 ; Sector translate table pointer
DW 0, 0, 0 ; Scratchpad area
DW CPM_VARS.dir_buffer ; Directory buffer pointer
DW CPM_VARS.DPB_C_RAM ; DPB Pointer
DW CPM_VARS.CHK_VEC_C ; Check Vector pointer
DW CPM_VARS.AL_MAP_C ; Allocation map pointer
res_data: ; offset 0xda28
DB 1, 8, 6, 4, 2, 9, 7, 5, 3
DPB_END EQU $
DB 0x0e, 3
; -------------------------------------------------------
; Filler to align blocks in ROM
; -------------------------------------------------------
LAST EQU $
CODE_SIZE EQU LAST-0xD600
FILL_SIZE EQU 0x500-CODE_SIZE
DISPLAY "| BIOS\t| ",/H,boot_f," | ",/H,CODE_SIZE," | ",/H,FILL_SIZE," |"
IFDEF CHECK_INTEGRITY
; Check integrity
ASSERT bios_wboot = 0xd6a8
ASSERT sel_disk = 0xd781
ASSERT home = 0xd7a7
ASSERT ram_disk_calc_addr = 0xd7eb
ASSERT write_phys_op = 0xd81e
ASSERT base_read_write = 0xd88a
ASSERT calc_sec_addr_in_bfr = 0xd8e4
ASSERT slicer_save_buffer = 0xd928
ASSERT print_strz = 0xd95e
ASSERT msg_hello = 0xd96b
ASSERT dpb_ram = 0xd9af
ASSERT dph_disk_a = 0xd9f8
ASSERT res_data = 0xda28
ENDIF
FILLER:
DS FILL_SIZE, 0xff
ENDMODULE
IFNDEF BUILD_ROM
OUTEND
ENDIF