use super::{
BDA_KBBUF_END, BDA_KBBUF_START, BDA_KBFLAG, BDA_KBHEAD, BDA_KBTAIL, F_AX, F_FLAGS, FLAG_ZF,
Labels, ds_bda, enter, leave,
};
use crate::fw::asm16::{AH, AL, AX, Alu, Asm, BH, BL, BX, CS, Cc, DI, DL, DS, DX, Mem, SI};
const KEY_TABLE_LEN: usize = 0x59;
fn put(table: &mut [u8; KEY_TABLE_LEN], at: usize, text: &[u8]) {
table[at..at + text.len()].copy_from_slice(text);
}
fn plain_table() -> [u8; KEY_TABLE_LEN] {
let mut t = [0u8; KEY_TABLE_LEN];
t[0x01] = 0x1b; put(&mut t, 0x02, b"1234567890-=");
t[0x0e] = 0x08; t[0x0f] = 0x09; put(&mut t, 0x10, b"qwertyuiop[]");
t[0x1c] = 0x0d; put(&mut t, 0x1e, b"asdfghjkl;'`");
put(&mut t, 0x2b, b"\\zxcvbnm,./");
t[0x37] = b'*'; t[0x39] = b' ';
put(&mut t, 0x47, b"789-456+1230.");
t
}
fn shift_table() -> [u8; KEY_TABLE_LEN] {
let mut t = [0u8; KEY_TABLE_LEN];
t[0x01] = 0x1b;
put(&mut t, 0x02, b"!@#$%^&*()_+");
t[0x0e] = 0x08;
t[0x0f] = 0x09;
put(&mut t, 0x10, b"QWERTYUIOP{}");
t[0x1c] = 0x0d;
put(&mut t, 0x1e, b"ASDFGHJKL:\"~");
put(&mut t, 0x2b, b"|ZXCVBNM<>?");
t[0x37] = b'*';
t[0x39] = b' ';
put(&mut t, 0x47, b"789-456+1230.");
t
}
#[allow(clippy::too_many_lines)]
pub(super) fn emit(a: &mut Asm, l: &Labels) {
a.bind(l.int09);
a.pushs(DS);
a.push(AX);
a.push(BX);
a.push(DX);
a.push(SI);
a.cld();
ds_bda(a);
let eoi = a.label();
let modifier = a.label();
let mod_up = a.label();
let shift_key = a.label();
let ctrl_key = a.label();
let alt_key = a.label();
let translate = a.label();
a.in_al(0x60);
a.alui8(Alu::CMP, AL, 0xe0);
a.jcc(Cc::E, eoi);
a.mov8(AH, AL);
a.alui8(Alu::AND, AH, 0x7f);
a.alui8(Alu::CMP, AH, 0x2a);
a.jcc(Cc::E, shift_key);
a.alui8(Alu::CMP, AH, 0x36);
a.jcc(Cc::E, shift_key);
a.alui8(Alu::CMP, AH, 0x1d);
a.jcc(Cc::E, ctrl_key);
a.alui8(Alu::CMP, AH, 0x38);
a.jcc(Cc::E, alt_key);
a.testi8(AL, 0x80);
a.jcc(Cc::NE, eoi);
a.jmp(translate);
a.bind(shift_key);
a.movi8(BL, 0x03);
a.jmp(modifier);
a.bind(ctrl_key);
a.movi8(BL, 0x04);
a.jmp(modifier);
a.bind(alt_key);
a.movi8(BL, 0x08);
a.bind(modifier);
a.testi8(AL, 0x80);
a.jcc(Cc::NE, mod_up);
a.aluto8(Alu::OR, Mem::abs(BDA_KBFLAG), BL);
a.jmp(eoi);
a.bind(mod_up);
a.not8(BL);
a.aluto8(Alu::AND, Mem::abs(BDA_KBFLAG), BL);
a.jmp(eoi);
a.bind(translate);
let no_shift = a.label();
let no_ctrl = a.label();
a.mov8(BH, AH);
a.mov8(DL, Mem::abs(BDA_KBFLAG));
a.alui8(Alu::CMP, BH, KEY_TABLE_LEN as u8);
a.jcc(Cc::AE, eoi);
a.mov8(AL, BH);
a.movi8(AH, 0);
a.movi_label(SI, l.kb_scan_plain);
a.testi8(DL, 0x03);
a.jcc(Cc::E, no_shift);
a.movi_label(SI, l.kb_scan_shift);
a.bind(no_shift);
a.alu(Alu::ADD, SI, AX);
a.mov8(AL, Mem::si(0).seg(CS));
a.alui8(Alu::CMP, AL, 0);
a.jcc(Cc::E, eoi);
a.testi8(DL, 0x04);
a.jcc(Cc::E, no_ctrl);
a.alui8(Alu::AND, AL, 0x1f);
a.bind(no_ctrl);
a.mov8(AH, BH);
a.call(l.kb_enqueue);
a.bind(eoi);
a.movi8(AL, 0x20);
a.out_al(0x20);
a.pop(SI);
a.pop(DX);
a.pop(BX);
a.pop(AX);
a.pops(DS);
a.iret();
a.bind(l.kb_enqueue);
a.push(BX);
a.push(DI);
let wrap_ok = a.label();
let full = a.label();
a.mov(BX, Mem::abs(BDA_KBTAIL));
a.mov(DI, BX);
a.alui(Alu::ADD, BX, 2);
a.alu(Alu::CMP, BX, Mem::abs(BDA_KBBUF_END));
a.jcc(Cc::B, wrap_ok);
a.mov(BX, Mem::abs(BDA_KBBUF_START));
a.bind(wrap_ok);
a.alu(Alu::CMP, BX, Mem::abs(BDA_KBHEAD));
a.jcc(Cc::E, full);
a.movto(Mem::di(0), AX);
a.movto(Mem::abs(BDA_KBTAIL), BX);
a.bind(full);
a.pop(DI);
a.pop(BX);
a.ret();
a.bind(l.int16);
enter(a);
ds_bda(a);
let wait_key = a.label();
let peek_key = a.label();
let shift_flags = a.label();
let done = a.label();
let no_translate = a.label();
a.mov8(AH, Mem::bp(F_AX + 1));
a.alui8(Alu::CMP, AH, 0x10);
a.jcc(Cc::B, no_translate);
a.alui8(Alu::CMP, AH, 0x12);
a.jcc(Cc::A, done);
a.alui8(Alu::SUB, AH, 0x10);
a.bind(no_translate);
a.alui8(Alu::CMP, AH, 0x00);
a.jcc(Cc::E, wait_key);
a.alui8(Alu::CMP, AH, 0x01);
a.jcc(Cc::E, peek_key);
a.alui8(Alu::CMP, AH, 0x02);
a.jcc(Cc::E, shift_flags);
a.jmp(done);
a.bind(wait_key);
let again = a.here_label();
let have = a.label();
let take_wrap = a.label();
a.cli();
a.mov(BX, Mem::abs(BDA_KBHEAD));
a.alu(Alu::CMP, BX, Mem::abs(BDA_KBTAIL));
a.jcc(Cc::NE, have);
a.sti();
a.hlt();
a.jmp(again);
a.bind(have);
a.mov(AX, Mem::bx(0));
a.alui(Alu::ADD, BX, 2);
a.alu(Alu::CMP, BX, Mem::abs(BDA_KBBUF_END));
a.jcc(Cc::B, take_wrap);
a.mov(BX, Mem::abs(BDA_KBBUF_START));
a.bind(take_wrap);
a.movto(Mem::abs(BDA_KBHEAD), BX);
a.sti();
a.movto(Mem::bp(F_AX), AX);
a.jmp(done);
a.bind(peek_key);
let empty = a.label();
a.mov(BX, Mem::abs(BDA_KBHEAD));
a.alu(Alu::CMP, BX, Mem::abs(BDA_KBTAIL));
a.jcc(Cc::E, empty);
a.mov(AX, Mem::bx(0));
a.movto(Mem::bp(F_AX), AX);
a.alui(Alu::AND, Mem::bp(F_FLAGS), !FLAG_ZF);
a.jmp(done);
a.bind(empty);
a.alui(Alu::OR, Mem::bp(F_FLAGS), FLAG_ZF);
a.jmp(done);
a.bind(shift_flags);
a.mov8(AL, Mem::abs(BDA_KBFLAG));
a.movto8(Mem::bp(F_AX), AL);
a.bind(done);
leave(a);
a.bind(l.kb_scan_plain);
a.db(&plain_table());
a.bind(l.kb_scan_shift);
a.db(&shift_table());
}