use super::{
BDA_EQUIPMENT, BDA_MEMSIZE, BDA_MOTOR, BDA_MOTOR_TIMEOUT, BDA_ROLLOVER, BDA_TICKS, E820_ENTRY,
EBDA_E820, EBDA_E820_COUNT, EBDA_GDTR, EBDA_SEGMENT, F_AX, F_CX, F_DX, FLAG_CF, Labels,
POST_STACK, clear_cf, ds_bda, enter, leave, load_seg, set_cf,
};
use crate::fw::asm16::{
AH, AL, AX, Alu, Asm, BH, BL, BP, BX, CS, CX, Cc, DI, DL, DS, DX, ES, Mem, SI, SP, SS, Shift,
};
const G_ESI: i32 = 4;
const G_EBX: i32 = 16;
const G_EDX: i32 = 20;
const G_ECX: i32 = 24;
const G_EAX: i32 = 28;
const G_FLAGS: i32 = 40;
const SMAP: u32 = 0x534d_4150;
const TICKS_PER_DAY: u32 = 0x0018_00b0;
#[allow(clippy::too_many_lines)]
pub(super) fn emit(a: &mut Asm, l: &Labels) {
a.bind(l.int08);
a.pushs(DS);
a.push(AX);
a.push(DX);
ds_bda(a);
let no_roll = a.label();
let no_motor = a.label();
a.incm32(Mem::abs(BDA_TICKS));
a.alui32(Alu::CMP, Mem::abs(BDA_TICKS), TICKS_PER_DAY);
a.jcc(Cc::B, no_roll);
a.movmi32(Mem::abs(BDA_TICKS), 0);
a.incm8(Mem::abs(BDA_ROLLOVER));
a.bind(no_roll);
a.alui8(Alu::CMP, Mem::abs(BDA_MOTOR_TIMEOUT), 0);
a.jcc(Cc::E, no_motor);
a.decm8(Mem::abs(BDA_MOTOR_TIMEOUT));
a.jcc(Cc::NE, no_motor);
a.movi(DX, 0x03f2);
a.movi8(AL, 0x0c);
a.out_dx_al();
a.movmi8(Mem::abs(BDA_MOTOR), 0);
a.bind(no_motor);
a.movi8(AL, 0x20);
a.out_al(0x20);
a.pop(DX);
a.pop(AX);
a.pops(DS);
a.int(0x1c);
a.iret();
a.bind(l.int11);
a.pushs(DS);
ds_bda(a);
a.mov(AX, Mem::abs(BDA_EQUIPMENT));
a.pops(DS);
a.iret();
a.bind(l.int12);
a.pushs(DS);
ds_bda(a);
a.mov(AX, Mem::abs(BDA_MEMSIZE));
a.pops(DS);
a.iret();
a.bind(l.int15);
a.sti();
a.pushs(DS);
a.pushs(ES);
a.pushad();
a.mov(BP, SP);
a.cld();
let ext_size = a.label();
let block_move = a.label();
let e8xx = a.label();
let e801 = a.label();
let e820 = a.label();
let fail = a.label();
let g_done = a.label();
a.mov8(AH, Mem::bp(G_EAX + 1));
a.alui8(Alu::CMP, AH, 0x88);
a.jcc(Cc::E, ext_size);
a.alui8(Alu::CMP, AH, 0x87);
a.jcc(Cc::E, block_move);
a.alui8(Alu::CMP, AH, 0xe8);
a.jcc(Cc::E, e8xx);
a.jmp(fail);
a.bind(e8xx);
a.mov8(AL, Mem::bp(G_EAX));
a.alui8(Alu::CMP, AL, 0x20);
a.jcc(Cc::E, e820);
a.alui8(Alu::CMP, AL, 0x01);
a.jcc(Cc::E, e801);
a.jmp(fail);
a.bind(ext_size);
a.movi8(AL, 0x30);
a.call(l.cmos_read);
a.mov8(BL, AL);
a.movi8(AL, 0x31);
a.call(l.cmos_read);
a.mov8(BH, AL);
a.movto(Mem::bp(G_EAX), BX);
a.alui(Alu::AND, Mem::bp(G_FLAGS), !FLAG_CF);
a.jmp(g_done);
a.bind(e801);
let capped = a.label();
a.movi8(AL, 0x30);
a.call(l.cmos_read);
a.mov8(BL, AL);
a.movi8(AL, 0x31);
a.call(l.cmos_read);
a.mov8(BH, AL);
a.alui(Alu::CMP, BX, 0x3c00);
a.jcc(Cc::BE, capped);
a.movi(BX, 0x3c00);
a.bind(capped);
a.movto(Mem::bp(G_EAX), BX);
a.movto(Mem::bp(G_ECX), BX);
a.movi8(AL, 0x34);
a.call(l.cmos_read);
a.mov8(BL, AL);
a.movi8(AL, 0x35);
a.call(l.cmos_read);
a.mov8(BH, AL);
a.movto(Mem::bp(G_EBX), BX);
a.movto(Mem::bp(G_EDX), BX);
a.alui(Alu::AND, Mem::bp(G_FLAGS), !FLAG_CF);
a.jmp(g_done);
a.bind(e820);
a.mov32(AX, Mem::bp(G_EDX));
a.alui32(Alu::CMP, AX, SMAP);
a.jcc(Cc::NE, fail);
load_seg(a, DS, EBDA_SEGMENT, AX);
a.movi32(CX, 0);
a.mov(CX, Mem::abs(EBDA_E820_COUNT));
a.mov32(BX, Mem::bp(G_EBX));
a.alu32(Alu::CMP, BX, CX);
a.jcc(Cc::AE, fail);
a.mov(AX, BX);
a.movi(CX, E820_ENTRY);
a.mul(CX);
a.mov(SI, AX);
a.alui(Alu::ADD, SI, EBDA_E820);
a.push(DI);
a.movi(CX, E820_ENTRY / 2);
a.rep();
a.movsw();
a.pop(DI);
a.movi32(AX, SMAP);
a.movto32(Mem::bp(G_EAX), AX);
a.movi32(CX, u32::from(E820_ENTRY));
a.movto32(Mem::bp(G_ECX), CX);
let not_last = a.label();
a.movi32(CX, 0);
a.mov(CX, Mem::abs(EBDA_E820_COUNT));
a.mov32(BX, Mem::bp(G_EBX));
a.alui32(Alu::ADD, BX, 1);
a.alu32(Alu::CMP, BX, CX);
a.jcc(Cc::B, not_last);
a.movi32(BX, 0);
a.bind(not_last);
a.movto32(Mem::bp(G_EBX), BX);
a.alui(Alu::AND, Mem::bp(G_FLAGS), !FLAG_CF);
a.jmp(g_done);
a.bind(block_move);
let bad_descriptor = a.label();
let flush = a.label();
a.cli();
a.mov(SI, Mem::bp(G_ESI));
a.testi8(Mem::si(0x15).seg(ES), 0x80);
a.jcc(Cc::E, bad_descriptor);
a.testi8(Mem::si(0x1d).seg(ES), 0x80);
a.jcc(Cc::E, bad_descriptor);
a.movrs(AX, ES);
a.movi32(BX, 0);
a.mov(BX, AX);
a.shift32(Shift::SHL, BX, 4);
a.movi32(AX, 0);
a.mov(AX, Mem::bp(G_ESI));
a.alu32(Alu::ADD, BX, AX);
load_seg(a, DS, EBDA_SEGMENT, AX);
a.movmi(Mem::abs(EBDA_GDTR), 6 * 8 - 1);
a.movto32(Mem::abs(EBDA_GDTR + 2), BX);
a.lgdt(Mem::abs(EBDA_GDTR));
a.movi32(CX, 0);
a.mov(CX, Mem::bp(G_ECX));
a.read_cr0(AX);
a.alui32(Alu::OR, AX, 1);
a.write_cr0(AX);
a.movi(BX, 0x10); a.movsr(DS, BX);
a.movi(BX, 0x18); a.movsr(ES, BX);
a.read_cr0(AX);
a.alui32(Alu::AND, AX, !1u32);
a.write_cr0(AX);
a.jmp(flush);
a.bind(flush);
a.movi(SI, 0);
a.movi(DI, 0);
a.cld();
a.rep();
a.movsw();
a.movmi8(Mem::bp(G_EAX + 1), 0x00);
a.alui(Alu::AND, Mem::bp(G_FLAGS), !FLAG_CF);
a.jmp(g_done);
a.bind(bad_descriptor);
a.movmi8(Mem::bp(G_EAX + 1), 0x02);
a.alui(Alu::OR, Mem::bp(G_FLAGS), FLAG_CF);
a.jmp(g_done);
a.bind(fail);
a.movmi8(Mem::bp(G_EAX + 1), 0x86);
a.alui(Alu::OR, Mem::bp(G_FLAGS), FLAG_CF);
a.bind(g_done);
a.popad();
a.pops(ES);
a.pops(DS);
a.iret();
a.bind(l.int1a);
enter(a);
ds_bda(a);
let get_ticks = a.label();
let set_ticks = a.label();
let get_time = a.label();
let get_date = a.label();
let t_done = a.label();
let t_fail = a.label();
a.mov8(AH, Mem::bp(F_AX + 1));
for (function, target) in [
(0x00u8, get_ticks),
(0x01, set_ticks),
(0x02, get_time),
(0x04, get_date),
] {
a.alui8(Alu::CMP, AH, function);
a.jcc(Cc::E, target);
}
a.jmp(t_fail);
a.bind(get_ticks);
a.mov(AX, Mem::abs(BDA_TICKS + 2));
a.movto(Mem::bp(F_CX), AX);
a.mov(AX, Mem::abs(BDA_TICKS));
a.movto(Mem::bp(F_DX), AX);
a.mov8(AL, Mem::abs(BDA_ROLLOVER));
a.movto8(Mem::bp(F_AX), AL);
a.movmi8(Mem::abs(BDA_ROLLOVER), 0);
a.jmp(t_done);
a.bind(set_ticks);
a.mov(AX, Mem::bp(F_CX));
a.movto(Mem::abs(BDA_TICKS + 2), AX);
a.mov(AX, Mem::bp(F_DX));
a.movto(Mem::abs(BDA_TICKS), AX);
a.movmi8(Mem::abs(BDA_ROLLOVER), 0);
a.jmp(t_done);
a.bind(get_time);
for (index, slot) in [(0x04u8, F_CX + 1), (0x02, F_CX), (0x00, F_DX + 1)] {
a.movi8(AL, index);
a.call(l.cmos_read);
a.movto8(Mem::bp(slot), AL);
}
a.movmi8(Mem::bp(F_DX), 0);
a.jmp(t_done);
a.bind(get_date);
for (index, slot) in [
(0x32u8, F_CX + 1),
(0x09, F_CX),
(0x08, F_DX + 1),
(0x07, F_DX),
] {
a.movi8(AL, index);
a.call(l.cmos_read);
a.movto8(Mem::bp(slot), AL);
}
a.bind(t_done);
clear_cf(a);
let t_leave = a.label();
a.jmp(t_leave);
a.bind(t_fail);
set_cf(a);
a.bind(t_leave);
leave(a);
a.bind(l.int19);
a.cli();
a.movi(AX, 0);
a.movsr(DS, AX);
a.movsr(ES, AX);
a.movsr(SS, AX);
a.movi(SP, POST_STACK);
a.sti();
let try_boot = a.label();
a.movi8(DL, 0x80);
a.call(try_boot);
a.movi8(DL, 0x00);
a.call(try_boot);
a.int(0x18);
a.bind(try_boot);
let no_boot = a.label();
let booting = a.label();
a.push(DX);
a.movi8(AH, 0x00);
a.int(0x13);
a.pop(DX);
a.push(DX);
a.movi(AX, 0x0201);
a.movi(CX, 0x0001);
a.movi8(crate::fw::asm16::DH, 0x00);
a.movi(BX, 0x7c00);
a.int(0x13);
a.pop(DX);
a.jcc(Cc::B, no_boot);
a.alui(Alu::CMP, Mem::abs(0x7dfe), 0xaa55);
a.jcc(Cc::NE, no_boot);
a.push(DX);
a.movi_label(SI, booting);
a.call(l.puts);
a.pop(DX);
a.jmpf(0x0000, 0x7c00);
a.bind(no_boot);
a.ret();
a.bind(l.int18);
let no_disk = a.label();
a.movi_label(SI, no_disk);
a.call(l.puts);
let park = a.here_label();
a.hlt();
a.jmp(park);
a.bind(l.unimplemented);
a.push(BP);
a.mov(BP, SP);
a.alui(Alu::OR, Mem::bp(6), FLAG_CF);
a.pop(BP);
a.iret();
a.bind(l.iret_stub);
a.iret();
a.bind(l.eoi_master);
a.push(AX);
a.movi8(AL, 0x20);
a.out_al(0x20);
a.pop(AX);
a.iret();
a.bind(l.eoi_slave);
a.push(AX);
a.movi8(AL, 0x20);
a.out_al(0xa0);
a.out_al(0x20);
a.pop(AX);
a.iret();
a.bind(booting);
a.db(b"Booting from 0000:7c00\r\n");
a.db(&[0]);
a.bind(no_disk);
a.db(b"No bootable device.\r\n");
a.db(&[0]);
let _ = CS;
}