use super::{
EBDA_COMMAND, EBDA_FD_CMD, EBDA_FD_COUNT, EBDA_FD_CYLINDER, EBDA_FD_DONE, EBDA_FD_HEAD,
EBDA_FD_RESULT, EBDA_FD_SECTOR, EBDA_FD_SPT, EBDA_HD_CAPACITY, EBDA_HD_CYLINDERS,
EBDA_HD_FLAGS, EBDA_HD_HEADS, EBDA_HD_SECTORS, EBDA_LBA_HIGH, EBDA_LBA_LOW, F_AX, F_BX, F_CX,
F_DS, F_DX, F_ES, F_SI, Labels, clear_cf, ds_ebda, enter, leave, set_cf,
};
use crate::fw::asm16::{
AH, AL, AX, Alu, Asm, BH, BL, BX, CH, CL, CS, CX, Cc, DH, DI, DL, DS, DX, ES, Mem, SI, Shift,
};
const CMD_BASE: u16 = 0x01f0;
const FDC_DOR: u16 = 0x03f2;
const FDC_MSR: u16 = 0x03f4;
const FDC_DATA: u16 = 0x03f5;
const FDC_CCR: u16 = 0x03f7;
#[allow(clippy::too_many_lines)]
pub(super) fn emit(a: &mut Asm, l: &Labels) {
a.bind(l.int13);
enter(a);
a.cld();
ds_ebda(a);
let floppy = a.label();
let read = a.label();
let write = a.label();
let params = a.label();
let kind = a.label();
let ext_check = a.label();
let ext_read = a.label();
let done = a.label();
a.mov8(DL, Mem::bp(F_DX));
a.mov8(AH, Mem::bp(F_AX + 1));
a.testi8(DL, 0x80);
a.jcc(Cc::E, floppy);
a.alui8(Alu::CMP, DL, 0x80);
a.jcc(Cc::NE, l.disk_fail);
a.testi8(Mem::abs(EBDA_HD_FLAGS), 0x01);
a.jcc(Cc::E, l.disk_fail);
for (function, target) in [
(0x00u8, l.disk_ok), (0x01, l.disk_ok), (0x02, read),
(0x03, write),
(0x04, l.disk_ok), (0x08, params),
(0x15, kind),
(0x41, ext_check),
(0x42, ext_read),
] {
a.alui8(Alu::CMP, AH, function);
a.jcc(Cc::E, target);
}
a.jmp(l.disk_fail);
a.bind(floppy);
let fd_reset = a.label();
let fd_read = a.label();
let fd_write = a.label();
let fd_params = a.label();
let fd_kind = a.label();
a.alui8(Alu::CMP, DL, 0x00);
a.jcc(Cc::NE, l.disk_fail);
for (function, target) in [
(0x00u8, fd_reset),
(0x01, l.disk_ok),
(0x02, fd_read),
(0x03, fd_write),
(0x04, l.disk_ok),
(0x08, fd_params),
(0x15, fd_kind),
] {
a.alui8(Alu::CMP, AH, function);
a.jcc(Cc::E, target);
}
a.jmp(l.disk_fail);
a.bind(fd_reset);
a.call(l.fd_start);
a.jmp(l.disk_ok);
a.bind(fd_params);
a.call(l.fd_geometry);
a.movi8(CH, 79);
a.mov8(CL, Mem::abs(EBDA_FD_SPT));
a.movto(Mem::bp(F_CX), CX);
a.movi8(DH, 1);
a.movi8(DL, 1);
a.movto(Mem::bp(F_DX), DX);
a.movmi8(Mem::bp(F_BX), 0x04);
a.jmp(l.disk_ok);
a.bind(fd_kind);
a.movmi8(Mem::bp(F_AX + 1), 0x01);
clear_cf(a);
a.jmp(done);
a.bind(fd_read);
a.movi8(AL, 0x46); let fd_transfer = a.label();
a.jmp(fd_transfer);
a.bind(fd_write);
a.movi8(AL, 0x45); a.bind(fd_transfer);
a.movto8(Mem::abs(EBDA_FD_CMD), AL);
let fd_loop = a.label();
let fd_stop = a.label();
let fd_finished = a.label();
let fd_same_track = a.label();
let fd_seek_again = a.label();
a.mov(AX, Mem::bp(F_AX));
a.alui(Alu::AND, AX, 0x00ff);
a.jcc(Cc::E, l.disk_ok);
a.movto(Mem::abs(EBDA_FD_COUNT), AX);
a.movmi8(Mem::abs(EBDA_FD_DONE), 0);
a.mov(CX, Mem::bp(F_CX));
a.movto8(Mem::abs(EBDA_FD_CYLINDER), CH);
a.mov8(AL, CL);
a.alui8(Alu::AND, AL, 0x3f);
a.movto8(Mem::abs(EBDA_FD_SECTOR), AL);
a.mov8(AL, Mem::bp(F_DX + 1));
a.alui8(Alu::AND, AL, 0x01);
a.movto8(Mem::abs(EBDA_FD_HEAD), AL);
a.mov(BX, Mem::bp(F_BX));
a.movsr(ES, Mem::bp(F_ES));
a.call(l.fd_geometry);
a.call(l.fd_start);
a.call(l.fd_seek);
a.bind(fd_loop);
a.call(l.fd_dma);
a.call(l.fd_xfer_one);
a.jcc(Cc::B, fd_stop);
a.incm8(Mem::abs(EBDA_FD_DONE));
a.alui(Alu::ADD, BX, 512);
a.decm(Mem::abs(EBDA_FD_COUNT));
a.jcc(Cc::E, fd_finished);
a.mov8(AL, Mem::abs(EBDA_FD_SECTOR));
a.incm8(AL);
a.alu8(Alu::CMP, AL, Mem::abs(EBDA_FD_SPT));
a.jcc(Cc::BE, fd_same_track);
a.movmi8(Mem::abs(EBDA_FD_SECTOR), 1);
a.mov8(AL, Mem::abs(EBDA_FD_HEAD));
a.alui8(Alu::XOR, AL, 0x01);
a.movto8(Mem::abs(EBDA_FD_HEAD), AL);
a.alui8(Alu::CMP, AL, 0);
a.jcc(Cc::NE, fd_seek_again);
a.incm8(Mem::abs(EBDA_FD_CYLINDER));
a.bind(fd_seek_again);
a.call(l.fd_seek);
a.jmp(fd_loop);
a.bind(fd_same_track);
a.movto8(Mem::abs(EBDA_FD_SECTOR), AL);
a.jmp(fd_loop);
a.bind(fd_finished);
a.mov8(AL, Mem::abs(EBDA_FD_DONE));
a.movto8(Mem::bp(F_AX), AL);
a.jmp(l.disk_ok);
a.bind(fd_stop);
a.mov8(AL, Mem::abs(EBDA_FD_DONE));
a.movto8(Mem::bp(F_AX), AL);
a.jmp(l.disk_fail);
a.bind(read);
a.movi8(BL, 0x20); let transfer = a.label();
a.jmp(transfer);
a.bind(write);
a.movi8(BL, 0x30); a.bind(transfer);
a.call(l.chs_to_lba);
a.jcc(Cc::B, l.disk_fail);
a.mov(CX, Mem::bp(F_AX));
a.alui(Alu::AND, CX, 0x00ff);
a.jcc(Cc::E, l.disk_ok);
a.mov8(AL, BL);
a.mov(BX, Mem::bp(F_BX));
a.movsr(ES, Mem::bp(F_ES));
a.call(l.ata_read);
a.jcc(Cc::B, l.disk_fail);
a.jmp(l.disk_ok);
a.bind(params);
a.mov(AX, Mem::abs(EBDA_HD_CYLINDERS));
a.dec(AX);
a.mov8(CH, AL);
a.mov8(CL, AH);
a.shift8(Shift::SHL, CL, 6);
a.mov(AX, Mem::abs(EBDA_HD_SECTORS));
a.alui8(Alu::AND, AL, 0x3f);
a.aluto8(Alu::OR, CL, AL);
a.movto(Mem::bp(F_CX), CX);
a.mov(AX, Mem::abs(EBDA_HD_HEADS));
a.dec(AX);
a.movto8(Mem::bp(F_DX + 1), AL);
a.movi8(AL, 1);
a.movto8(Mem::bp(F_DX), AL);
a.jmp(l.disk_ok);
a.bind(kind);
a.mov(AX, Mem::abs(EBDA_HD_CAPACITY + 2));
a.movto(Mem::bp(F_CX), AX);
a.mov(AX, Mem::abs(EBDA_HD_CAPACITY));
a.movto(Mem::bp(F_DX), AX);
a.movmi8(Mem::bp(F_AX + 1), 3);
clear_cf(a);
a.jmp(done);
a.bind(ext_check);
a.mov(AX, Mem::bp(F_BX));
a.alui(Alu::CMP, AX, 0x55aa);
a.jcc(Cc::NE, l.disk_fail);
a.movmi(Mem::bp(F_BX), 0xaa55);
a.movmi(Mem::bp(F_CX), 0x0001);
a.movmi8(Mem::bp(F_AX + 1), 0x21);
clear_cf(a);
a.jmp(done);
a.bind(ext_read);
a.pushs(DS);
a.movsr(DS, Mem::bp(F_DS));
a.mov(SI, Mem::bp(F_SI));
a.mov(CX, Mem::si(2));
a.mov(DI, Mem::si(4));
a.mov(AX, Mem::si(6));
a.mov(BX, Mem::si(8));
a.mov(DX, Mem::si(10));
a.pops(DS);
a.movto(Mem::abs(EBDA_LBA_LOW), BX);
a.movto(Mem::abs(EBDA_LBA_HIGH), DX);
a.movsr(ES, AX);
a.mov(BX, DI);
a.movi8(AL, 0x20);
a.call(l.ata_read);
a.jcc(Cc::B, l.disk_fail);
a.jmp(l.disk_ok);
a.bind(l.disk_ok);
a.movmi8(Mem::bp(F_AX + 1), 0x00);
clear_cf(a);
a.jmp(done);
a.bind(l.disk_fail);
a.movmi8(Mem::bp(F_AX + 1), 0x01);
set_cf(a);
a.bind(done);
leave(a);
a.bind(l.chs_to_lba);
a.push(BX);
a.push(CX);
a.push(DX);
let bad = a.label();
let out = a.label();
a.mov(CX, Mem::bp(F_CX));
a.mov8(AL, CH);
a.mov8(AH, CL);
a.shift8(Shift::SHR, AH, 6);
a.mov(BX, AX);
a.movi32(AX, 0);
a.mov(AX, BX);
a.movi32(BX, 0);
a.mov(BX, Mem::abs(EBDA_HD_HEADS));
a.mul32(BX);
a.movi32(BX, 0);
a.mov8(BL, Mem::bp(F_DX + 1));
a.alu32(Alu::ADD, AX, BX);
a.movi32(BX, 0);
a.mov(BX, Mem::abs(EBDA_HD_SECTORS));
a.mul32(BX);
a.movi32(BX, 0);
a.mov8(BL, Mem::bp(F_CX));
a.alui8(Alu::AND, BL, 0x3f);
a.jcc(Cc::E, bad);
a.dec(BX);
a.alu32(Alu::ADD, AX, BX);
a.movto32(Mem::abs(EBDA_LBA_LOW), AX);
a.clc();
a.jmp(out);
a.bind(bad);
a.stc();
a.bind(out);
a.pop(DX);
a.pop(CX);
a.pop(BX);
a.ret();
a.bind(l.ata_read);
a.push(AX);
a.push(CX);
a.push(DX);
a.push(SI);
a.push(DI);
let fail = a.label();
let finish = a.label();
let sector = a.label();
a.movto8(Mem::abs(EBDA_COMMAND), AL);
a.call(l.ata_wait_ready);
a.jcc(Cc::B, fail);
a.movi(DX, CMD_BASE + 6);
a.mov8(AL, Mem::abs(EBDA_LBA_LOW + 3));
a.alui8(Alu::AND, AL, 0x0f);
a.alui8(Alu::OR, AL, 0xe0); a.out_dx_al();
a.movi(DX, CMD_BASE + 2);
a.mov8(AL, CL);
a.out_dx_al();
a.movi(DX, CMD_BASE + 3);
a.mov8(AL, Mem::abs(EBDA_LBA_LOW));
a.out_dx_al();
a.movi(DX, CMD_BASE + 4);
a.mov8(AL, Mem::abs(EBDA_LBA_LOW + 1));
a.out_dx_al();
a.movi(DX, CMD_BASE + 5);
a.mov8(AL, Mem::abs(EBDA_LBA_LOW + 2));
a.out_dx_al();
a.movi(DX, CMD_BASE + 7);
a.mov8(AL, Mem::abs(EBDA_COMMAND));
a.out_dx_al();
a.bind(sector);
a.call(l.ata_wait_drq);
a.jcc(Cc::B, fail);
a.movi(DX, CMD_BASE);
a.push(CX);
a.movi(CX, 256);
let do_write = a.label();
let advance = a.label();
a.alui8(Alu::CMP, Mem::abs(EBDA_COMMAND), 0x30);
a.jcc(Cc::E, do_write);
a.mov(DI, BX);
a.rep();
a.insw();
a.mov(BX, DI);
a.jmp(advance);
a.bind(do_write);
a.pushs(DS);
a.movrs(AX, ES);
a.movsr(DS, AX);
a.mov(SI, BX);
a.rep();
a.outsw();
a.mov(BX, SI);
a.pops(DS);
a.bind(advance);
a.pop(CX);
a.dec(CX);
a.jcc(Cc::NE, sector);
a.call(l.ata_wait_ready);
a.jcc(Cc::B, fail);
a.clc();
a.jmp(finish);
a.bind(fail);
a.stc();
a.bind(finish);
a.pop(DI);
a.pop(SI);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.ata_wait_ready);
a.push(AX);
a.push(CX);
a.push(DX);
let r_ok = a.label();
a.movi(CX, 0);
a.movi(DX, CMD_BASE + 7);
let r_poll = a.here_label();
a.in_al_dx();
a.testi8(AL, 0x80);
a.jcc(Cc::E, r_ok);
a.dec(CX);
a.jcc(Cc::NE, r_poll);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.stc();
a.ret();
a.bind(r_ok);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.clc();
a.ret();
a.bind(l.ata_wait_drq);
a.push(AX);
a.push(CX);
a.push(DX);
let d_ok = a.label();
let d_err = a.label();
let d_next = a.label();
a.movi(CX, 0);
a.movi(DX, CMD_BASE + 7);
let d_poll = a.here_label();
a.in_al_dx();
a.testi8(AL, 0x80); a.jcc(Cc::NE, d_next);
a.testi8(AL, 0x21); a.jcc(Cc::NE, d_err);
a.testi8(AL, 0x08); a.jcc(Cc::NE, d_ok);
a.bind(d_next);
a.dec(CX);
a.jcc(Cc::NE, d_poll);
a.bind(d_err);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.stc();
a.ret();
a.bind(d_ok);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.clc();
a.ret();
diskette(a, l);
}
#[allow(clippy::too_many_lines)]
fn diskette(a: &mut Asm, l: &Labels) {
a.bind(l.fd_out);
a.push(AX);
a.push(CX);
a.push(DX);
let o_send = a.label();
let o_out = a.label();
a.mov8(AH, AL);
a.movi(CX, 0);
a.movi(DX, FDC_MSR);
let o_poll = a.here_label();
a.in_al_dx();
a.alui8(Alu::AND, AL, 0xc0);
a.alui8(Alu::CMP, AL, 0x80);
a.jcc(Cc::E, o_send);
a.dec(CX);
a.jcc(Cc::NE, o_poll);
a.jmp(o_out);
a.bind(o_send);
a.movi(DX, FDC_DATA);
a.mov8(AL, AH);
a.out_dx_al();
a.bind(o_out);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.fd_in);
a.push(CX);
a.push(DX);
let i_read = a.label();
let i_out = a.label();
a.movi(CX, 0);
a.movi(DX, FDC_MSR);
let i_poll = a.here_label();
a.in_al_dx();
a.alui8(Alu::AND, AL, 0xc0);
a.alui8(Alu::CMP, AL, 0xc0);
a.jcc(Cc::E, i_read);
a.dec(CX);
a.jcc(Cc::NE, i_poll);
a.movi8(AL, 0xff);
a.jmp(i_out);
a.bind(i_read);
a.movi(DX, FDC_DATA);
a.in_al_dx();
a.bind(i_out);
a.pop(DX);
a.pop(CX);
a.ret();
a.bind(l.fd_drain);
a.push(AX);
a.push(CX);
a.push(DX);
let dr_done = a.label();
a.movi(CX, 0);
let dr_poll = a.here_label();
a.movi(DX, FDC_MSR);
a.in_al_dx();
a.alui8(Alu::AND, AL, 0xd0);
a.alui8(Alu::CMP, AL, 0xd0);
a.jcc(Cc::NE, dr_done);
a.movi(DX, FDC_DATA);
a.in_al_dx();
a.dec(CX);
a.jcc(Cc::NE, dr_poll);
a.bind(dr_done);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.fd_start);
a.push(AX);
a.push(CX);
a.push(DX);
a.movi(DX, FDC_DOR);
a.movi8(AL, 0x1c);
a.out_dx_al();
a.movi(DX, FDC_CCR);
a.movi8(AL, 0x00); a.out_dx_al();
a.movi(CX, 4);
let st_drain = a.here_label();
a.movi8(AL, 0x08);
a.call(l.fd_out);
a.call(l.fd_drain);
a.dec(CX);
a.jcc(Cc::NE, st_drain);
a.movi8(AL, 0x03);
a.call(l.fd_out);
a.movi8(AL, 0xdf);
a.call(l.fd_out);
a.movi8(AL, 0x02);
a.call(l.fd_out);
a.pop(DX);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.fd_seek);
a.push(AX);
a.movi8(AL, 0x0f);
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_HEAD));
a.shift8(Shift::SHL, AL, 2);
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_CYLINDER));
a.call(l.fd_out);
a.movi8(AL, 0x08);
a.call(l.fd_out);
a.call(l.fd_drain);
a.pop(AX);
a.ret();
a.bind(l.fd_dma);
a.push(AX);
a.push(BX);
a.push(CX);
a.push(DX);
a.movrs(AX, ES);
a.mov(DX, AX);
a.shift(Shift::SHR, DX, 12);
a.shift(Shift::SHL, AX, 4);
a.alu(Alu::ADD, AX, BX);
a.alui8(Alu::ADC, DL, 0);
a.mov(CX, AX);
a.movi8(AL, 0x06); a.out_al(0x0a);
a.movi8(AL, 0x00); a.out_al(0x0c);
let dma_mode = a.label();
a.movi8(AL, 0x46);
a.alui8(Alu::CMP, Mem::abs(EBDA_FD_CMD), 0x45);
a.jcc(Cc::NE, dma_mode);
a.movi8(AL, 0x4a);
a.bind(dma_mode);
a.out_al(0x0b);
a.mov8(AL, CL);
a.out_al(0x04);
a.mov8(AL, CH);
a.out_al(0x04);
a.mov8(AL, DL);
a.out_al(0x81); a.movi8(AL, 0x00);
a.out_al(0x0c);
a.movi8(AL, 0xff); a.out_al(0x05);
a.movi8(AL, 0x01);
a.out_al(0x05);
a.movi8(AL, 0x02); a.out_al(0x0a);
a.pop(DX);
a.pop(CX);
a.pop(BX);
a.pop(AX);
a.ret();
a.bind(l.fd_xfer_one);
a.push(AX);
a.push(CX);
a.push(DI);
let r_ok = a.label();
let r_out = a.label();
a.mov8(AL, Mem::abs(EBDA_FD_CMD));
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_HEAD));
a.shift8(Shift::SHL, AL, 2);
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_CYLINDER));
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_HEAD));
a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_SECTOR));
a.call(l.fd_out);
a.movi8(AL, 0x02); a.call(l.fd_out);
a.mov8(AL, Mem::abs(EBDA_FD_SECTOR)); a.call(l.fd_out);
a.movi8(AL, 0x1b); a.call(l.fd_out);
a.movi8(AL, 0xff); a.call(l.fd_out);
a.movi(DI, EBDA_FD_RESULT);
a.movi(CX, 7);
let r_res = a.here_label();
a.call(l.fd_in);
a.movto8(Mem::di(0), AL);
a.inc(DI);
a.dec(CX);
a.jcc(Cc::NE, r_res);
a.mov8(AL, Mem::abs(EBDA_FD_RESULT));
a.alui8(Alu::AND, AL, 0xc0);
a.jcc(Cc::E, r_ok);
a.stc();
a.jmp(r_out);
a.bind(r_ok);
a.clc();
a.bind(r_out);
a.pop(DI);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.fd_geometry);
a.push(AX);
a.push(BX);
a.push(SI);
let g_known = a.label();
let table = a.label();
a.movi8(AL, 0x10);
a.call(l.cmos_read);
a.shift8(Shift::SHR, AL, 4);
a.alui8(Alu::CMP, AL, 5);
a.jcc(Cc::B, g_known);
a.movi8(AL, 4);
a.bind(g_known);
a.mov8(BL, AL);
a.movi8(BH, 0);
a.movi_label(SI, table);
a.alu(Alu::ADD, SI, BX);
a.mov8(AL, Mem::si(0).seg(CS));
a.movto8(Mem::abs(EBDA_FD_SPT), AL);
a.pop(SI);
a.pop(BX);
a.pop(AX);
a.ret();
a.bind(table);
a.db(&[18, 9, 15, 9, 18]);
}