use super::{
BDA_ACTIVE_PAGE, BDA_CHAR_HEIGHT, BDA_COLUMNS, BDA_CRTC_PORT, BDA_CURSOR, BDA_CURSOR_SHAPE,
BDA_EBDA, BDA_EQUIPMENT, BDA_HD_COUNT, BDA_KBBUF, BDA_KBBUF_END, BDA_KBBUF_START, BDA_KBHEAD,
BDA_KBTAIL, BDA_MEMSIZE, BDA_MODE_SELECT, BDA_PAGE_OFFSET, BDA_PAGE_SIZE, BDA_ROWS,
BDA_VIDEO_MODE, E820_ENTRY, EBDA_E820, EBDA_E820_COUNT, EBDA_HD_CAPACITY, EBDA_HD_CYLINDERS,
EBDA_HD_FLAGS, EBDA_HD_HEADS, EBDA_HD_SECTORS, EBDA_SEGMENT, EBDA_SIZE, IDENTIFY_BUFFER,
KBBUF_BYTES, Labels, POST_STACK, SEGMENT, ds_bda,
};
use crate::fw::asm16::{
AH, AL, AX, Alu, Asm, BH, BL, BX, CH, CL, CX, Cc, DI, DS, DX, ES, Label, Mem, SI, SP, SS, Shift,
};
fn vector(a: &mut Asm, l: &Labels, number: u8, handler: Label) {
a.movi8(AL, number);
a.movi_label(BX, handler);
a.call(l.set_vector);
}
#[allow(clippy::too_many_lines)]
pub(super) fn emit(a: &mut Asm, l: &Labels) {
a.bind(l.post);
a.cli();
a.cld();
a.movi(AX, 0);
a.movsr(DS, AX);
a.movsr(ES, AX);
a.movsr(SS, AX);
a.movi(SP, POST_STACK);
a.in_al(0x92);
a.alui8(Alu::OR, AL, 0x02);
a.alui8(Alu::AND, AL, 0xfe);
a.out_al(0x92);
a.movi(DI, 0x400);
a.movi(CX, 0x100);
a.movi(AX, 0);
a.rep();
a.stosb();
a.movi(DI, 0);
a.movi(CX, 256);
let fill = a.here_label();
a.movi_label(AX, l.unimplemented);
a.stosw();
a.movi(AX, SEGMENT);
a.stosw();
a.dec(CX);
a.jcc(Cc::NE, fill);
vector(a, l, 0x08, l.int08);
vector(a, l, 0x09, l.int09);
for n in 0x0a..=0x0f {
vector(a, l, n, l.eoi_master);
}
vector(a, l, 0x10, l.int10);
vector(a, l, 0x11, l.int11);
vector(a, l, 0x12, l.int12);
vector(a, l, 0x13, l.int13);
vector(a, l, 0x15, l.int15);
vector(a, l, 0x16, l.int16);
vector(a, l, 0x18, l.int18);
vector(a, l, 0x19, l.int19);
vector(a, l, 0x1a, l.int1a);
vector(a, l, 0x05, l.iret_stub);
vector(a, l, 0x1b, l.iret_stub);
vector(a, l, 0x1c, l.iret_stub);
for n in 0x70..=0x77 {
vector(a, l, n, l.eoi_slave);
}
a.movi8(AL, 0x11); a.out_al(0x20);
a.out_al(0xa0);
a.movi8(AL, 0x08); a.out_al(0x21);
a.movi8(AL, 0x70); a.out_al(0xa1);
a.movi8(AL, 0x04); a.out_al(0x21);
a.movi8(AL, 0x02); a.out_al(0xa1);
a.movi8(AL, 0x01); a.out_al(0x21);
a.out_al(0xa1);
a.movi8(AL, 0xf8);
a.out_al(0x21);
a.movi8(AL, 0xff);
a.out_al(0xa1);
a.movi8(AL, 0x36);
a.out_al(0x43);
a.movi8(AL, 0x00);
a.out_al(0x40);
a.out_al(0x40);
a.movi8(AL, 0x0a);
a.out_al(0x70);
a.movi8(AL, 0x26);
a.out_al(0x71);
a.movi8(AL, 0x0b);
a.out_al(0x70);
a.movi8(AL, 0x02);
a.out_al(0x71);
a.movi8(AL, 0x0c);
a.out_al(0x70);
a.in_al(0x71);
a.movi8(AL, 0x0d);
a.out_al(0x70);
a.in_al(0x71);
ds_bda(a);
a.movi8(AL, 0x14);
a.call(l.cmos_read);
a.movi8(AH, 0);
a.movto(Mem::abs(BDA_EQUIPMENT), AX);
a.movi8(AL, 0x15);
a.call(l.cmos_read);
a.movto8(Mem::abs(BDA_MEMSIZE), AL);
a.movi8(AL, 0x16);
a.call(l.cmos_read);
a.movto8(Mem::abs(BDA_MEMSIZE + 1), AL);
a.mov(AX, Mem::abs(BDA_MEMSIZE));
a.dec(AX);
a.movto(Mem::abs(BDA_MEMSIZE), AX);
a.movmi(Mem::abs(BDA_EBDA), EBDA_SEGMENT);
a.movmi(Mem::abs(BDA_KBHEAD), BDA_KBBUF);
a.movmi(Mem::abs(BDA_KBTAIL), BDA_KBBUF);
a.movmi(Mem::abs(BDA_KBBUF_START), BDA_KBBUF);
a.movmi(Mem::abs(BDA_KBBUF_END), BDA_KBBUF + KBBUF_BYTES);
a.movmi8(Mem::abs(BDA_VIDEO_MODE), 0x03);
a.movmi(Mem::abs(BDA_COLUMNS), 80);
a.movmi(Mem::abs(BDA_PAGE_SIZE), 0x1000);
a.movmi(Mem::abs(BDA_PAGE_OFFSET), 0);
a.movmi(Mem::abs(BDA_CURSOR), 0);
a.movmi(Mem::abs(BDA_CURSOR_SHAPE), 0x0607);
a.movmi8(Mem::abs(BDA_ACTIVE_PAGE), 0);
a.movmi(Mem::abs(BDA_CRTC_PORT), 0x03d4);
a.movmi8(Mem::abs(BDA_MODE_SELECT), 0x29);
a.movmi8(Mem::abs(BDA_ROWS), 24);
a.movmi(Mem::abs(BDA_CHAR_HEIGHT), 16);
a.movmi8(Mem::abs(BDA_HD_COUNT), 0);
a.movi(AX, EBDA_SEGMENT);
a.movsr(ES, AX);
a.movmi8(Mem::abs(EBDA_SIZE).seg(ES), 1);
a.movi(AX, SEGMENT);
a.movsr(DS, AX);
a.movi_label(SI, l.e820_template);
a.movi(DI, EBDA_E820);
a.movi(CX, E820_ENTRY * 4 / 2);
a.rep();
a.movsw();
ds_bda(a);
a.movmi(Mem::abs(EBDA_E820_COUNT).seg(ES), 4);
a.movi32(AX, 0);
a.mov(AX, Mem::abs(BDA_MEMSIZE));
a.shift32(Shift::SHL, AX, 10);
a.movto32(Mem::abs(EBDA_E820 + 8).seg(ES), AX);
a.movto32(Mem::abs(EBDA_E820 + E820_ENTRY).seg(ES), AX);
a.movi8(AL, 0x34);
a.call(l.cmos_read);
a.mov8(CL, AL);
a.movi8(AL, 0x35);
a.call(l.cmos_read);
a.mov8(CH, AL);
a.movi32(DX, 0);
a.mov(DX, CX);
a.shift32(Shift::SHL, DX, 16);
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.movi32(AX, 0);
a.mov(AX, BX);
a.shift32(Shift::SHL, AX, 10);
a.alu32(Alu::ADD, AX, DX);
a.movto32(Mem::abs(EBDA_E820 + 3 * E820_ENTRY + 8).seg(ES), AX);
a.movi(BX, 0xc000);
let scan_loop = a.here_label();
let scan_step = a.label();
a.movsr(ES, BX);
a.alui(Alu::CMP, Mem::abs(0).seg(ES), 0xaa55);
a.jcc(Cc::NE, scan_step);
a.mov8(AL, Mem::abs(2).seg(ES));
a.alui8(Alu::CMP, AL, 0);
a.jcc(Cc::E, scan_step);
a.mov8(CL, AL);
a.movi8(CH, 0);
a.shift(Shift::SHL, CX, 9);
a.movi(SI, 0);
a.movi8(AL, 0);
let csum = a.here_label();
a.alu8(Alu::ADD, AL, Mem::si(0).seg(ES));
a.inc(SI);
a.dec(CX);
a.jcc(Cc::NE, csum);
a.alui8(Alu::CMP, AL, 0);
a.jcc(Cc::NE, scan_step);
let back = a.label();
a.push(BX);
a.pushs(crate::fw::asm16::CS);
a.pushi_label(back);
a.push(BX);
a.pushi(0x0003);
a.retf();
a.bind(back);
a.pop(BX);
ds_bda(a);
a.bind(scan_step);
a.alui(Alu::ADD, BX, 0x80);
a.alui(Alu::CMP, BX, 0xe000);
a.jcc(Cc::NE, scan_loop);
a.movi(AX, 0x0003);
a.int(0x10);
let banner = a.label();
let base_msg = a.label();
let ext_msg = a.label();
let end_msg = a.label();
a.movi_label(SI, banner);
a.call(l.puts);
a.mov(AX, Mem::abs(BDA_MEMSIZE));
a.call(l.put_dec);
a.movi_label(SI, base_msg);
a.call(l.puts);
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.mov(AX, BX);
a.call(l.put_dec);
a.movi_label(SI, ext_msg);
a.call(l.puts);
a.call(l.kbc_wait_write);
a.movi8(AL, 0xaa);
a.out_al(0x64);
a.call(l.kbc_wait_read);
a.call(l.kbc_wait_write);
a.movi8(AL, 0x60);
a.out_al(0x64);
a.call(l.kbc_wait_write);
a.movi8(AL, 0x45);
a.out_al(0x60);
a.call(l.kbc_wait_write);
a.movi8(AL, 0xae);
a.out_al(0x64);
a.call(l.kbc_wait_write);
a.movi8(AL, 0xf4);
a.out_al(0x60);
a.call(l.kbc_wait_read);
detect_hd(a, l);
a.movi_label(SI, end_msg);
a.call(l.puts);
a.sti();
a.int(0x19);
let wedged = a.here_label();
a.hlt();
a.jmp(wedged);
a.bind(l.set_vector);
a.push(DI);
a.push(AX);
a.movi8(AH, 0);
a.shift(Shift::SHL, AX, 2);
a.mov(DI, AX);
a.movto(Mem::di(0), BX);
a.movmi(Mem::di(2), SEGMENT);
a.pop(AX);
a.pop(DI);
a.ret();
a.bind(l.cmos_read);
a.out_al(0x70);
a.in_al(0x71);
a.ret();
a.bind(l.kbc_wait_write);
a.push(AX);
a.push(CX);
a.movi(CX, 0);
let ww = a.here_label();
let ww_done = a.label();
a.in_al(0x64);
a.testi8(AL, 0x02);
a.jcc(Cc::E, ww_done);
a.dec(CX);
a.jcc(Cc::NE, ww);
a.bind(ww_done);
a.pop(CX);
a.pop(AX);
a.ret();
a.bind(l.kbc_wait_read);
a.push(CX);
a.movi(CX, 0);
let wr = a.here_label();
let wr_have = a.label();
let wr_done = a.label();
a.in_al(0x64);
a.testi8(AL, 0x01);
a.jcc(Cc::NE, wr_have);
a.dec(CX);
a.jcc(Cc::NE, wr);
a.movi8(AL, 0xff);
a.jmp(wr_done);
a.bind(wr_have);
a.in_al(0x60);
a.bind(wr_done);
a.pop(CX);
a.ret();
a.bind(banner);
a.db(b"rsemu BIOS, ");
a.db(&[0]);
a.bind(base_msg);
a.db(b"K base, ");
a.db(&[0]);
a.bind(ext_msg);
a.db(b"K extended\r\n");
a.db(&[0]);
a.bind(end_msg);
a.db(b"Booting.\r\n");
a.db(&[0]);
e820_template(a, l);
}
fn e820_template(a: &mut Asm, l: &Labels) {
fn entry(a: &mut Asm, base: u64, length: u64, kind: u32) {
a.db(&base.to_le_bytes());
a.db(&length.to_le_bytes());
a.db(&kind.to_le_bytes());
}
a.bind(l.e820_template);
entry(a, 0x0000_0000, 0x0009_fc00, 1);
entry(a, 0x0009_fc00, 0x0000_0400, 2);
entry(a, 0x000f_0000, 0x0001_0000, 2);
entry(a, 0x0010_0000, 0x0000_0000, 1);
}
fn detect_hd(a: &mut Asm, l: &Labels) {
let none = a.label();
let done = a.label();
a.movi(DX, 0x03f6);
a.movi8(AL, 0x02);
a.out_dx_al();
a.movi(DX, 0x01f6);
a.movi8(AL, 0xa0);
a.out_dx_al();
a.call(l.ata_wait_ready);
a.jcc(Cc::B, none);
a.movi(DX, 0x01f7);
a.movi8(AL, 0xec);
a.out_dx_al();
a.in_al_dx();
a.alui8(Alu::CMP, AL, 0);
a.jcc(Cc::E, none);
a.call(l.ata_wait_drq);
a.jcc(Cc::B, none);
a.movi(AX, 0);
a.movsr(ES, AX);
a.movi(DI, IDENTIFY_BUFFER);
a.movi(DX, 0x01f0);
a.movi(CX, 256);
a.rep();
a.insw();
a.movi(AX, 0);
a.movsr(DS, AX);
a.movi(AX, EBDA_SEGMENT);
a.movsr(ES, AX);
a.movi(SI, IDENTIFY_BUFFER);
for (word, field) in [
(1u16, EBDA_HD_CYLINDERS),
(3, EBDA_HD_HEADS),
(6, EBDA_HD_SECTORS),
] {
a.mov(AX, Mem::si(i32::from(word) * 2));
a.movto(Mem::abs(field).seg(ES), AX);
}
a.mov(AX, Mem::si(60 * 2));
a.movto(Mem::abs(EBDA_HD_CAPACITY).seg(ES), AX);
a.mov(AX, Mem::si(61 * 2));
a.movto(Mem::abs(EBDA_HD_CAPACITY + 2).seg(ES), AX);
a.movi8(AL, 0x01);
a.mov8(AH, Mem::si(49 * 2 + 1));
let no_lba = a.label();
a.testi8(AH, 0x02);
a.jcc(Cc::E, no_lba);
a.alui8(Alu::OR, AL, 0x02);
a.bind(no_lba);
a.movto8(Mem::abs(EBDA_HD_FLAGS).seg(ES), AL);
ds_bda(a);
a.movmi8(Mem::abs(BDA_HD_COUNT), 1);
a.jmp(done);
a.bind(none);
ds_bda(a);
a.bind(done);
}