Initial import of ViperOS
This commit is contained in:
251
VKernel/Kernel/drivers/core/cpu/apic.py
Normal file
251
VKernel/Kernel/drivers/core/cpu/apic.py
Normal file
@@ -0,0 +1,251 @@
|
||||
import asm
|
||||
import intr.gdt as gdt
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.core.cpu.cpu as cpu
|
||||
import mm.mm as mm
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
IA32_APIC_BASE: t.CDefine = 0x1B
|
||||
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
|
||||
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
|
||||
|
||||
LAPIC_ID: t.CDefine = 0x020
|
||||
LAPIC_VERSION: t.CDefine = 0x030
|
||||
LAPIC_TPR: t.CDefine = 0x080
|
||||
LAPIC_EOI: t.CDefine = 0x0B0
|
||||
LAPIC_LDR: t.CDefine = 0x0D0
|
||||
LAPIC_SVR: t.CDefine = 0x0F0
|
||||
LAPIC_ISR0: t.CDefine = 0x100
|
||||
LAPIC_ICR_LOW: t.CDefine = 0x300
|
||||
LAPIC_ICR_HIGH: t.CDefine = 0x310
|
||||
LAPIC_LVT_TIMER: t.CDefine = 0x320
|
||||
LAPIC_LVT_LINT0: t.CDefine = 0x350
|
||||
LAPIC_LVT_LINT1: t.CDefine = 0x360
|
||||
LAPIC_LVT_ERROR: t.CDefine = 0x370
|
||||
LAPIC_TIMER_INIT: t.CDefine = 0x380
|
||||
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
|
||||
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
|
||||
|
||||
LAPIC_SVR_ENABLE: t.CDefine = 0x100
|
||||
LAPIC_LVT_MASKED: t.CDefine = 0x10000
|
||||
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
|
||||
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
|
||||
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
|
||||
|
||||
LAPIC_ICR_INIT: t.CDefine = 0x500
|
||||
LAPIC_ICR_STARTUP: t.CDefine = 0x600
|
||||
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
|
||||
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
|
||||
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
|
||||
|
||||
MAX_CPUS: t.CDefine = 8
|
||||
AP_TRAMPOLINE_ADDR: t.CDefine = 0x7000
|
||||
|
||||
_lapic_base: t.CStatic | t.CUInt64T = 0
|
||||
_cpu_count: t.CStatic | t.CUInt32T = 1
|
||||
_bsp_lapic_id: t.CStatic | t.CUInt32T = 0
|
||||
_ap_ready: t.CStatic | t.CUInt32T = 0
|
||||
|
||||
def read(offset: t.CUInt32T) -> t.CUInt32T:
|
||||
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
|
||||
return c.Deref(t.CUInt32T(addr, t.CPtr))
|
||||
|
||||
def write(offset: t.CUInt32T, value: t.CUInt32T):
|
||||
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
|
||||
c.Set(c.Deref(t.CUInt32T(addr, t.CPtr)), value)
|
||||
|
||||
def eoi():
|
||||
write(LAPIC_EOI, 0)
|
||||
|
||||
def get_id() -> t.CUInt32T:
|
||||
return read(LAPIC_ID) >> 24
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def init():
|
||||
global _lapic_base, _bsp_lapic_id
|
||||
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
|
||||
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
|
||||
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
|
||||
_bsp_lapic_id = read(LAPIC_ID) >> 24
|
||||
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
|
||||
write(LAPIC_TPR, 0)
|
||||
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
|
||||
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
|
||||
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_TIMER_DIVIDE, 0x0B)
|
||||
write(LAPIC_LDR, 0x01000000)
|
||||
eoi()
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_cpu_count() -> t.CUInt32T:
|
||||
res: cpu.cpuid_result
|
||||
cpu.cpuid(0, c.Addr(res))
|
||||
max_leaf: t.CUInt32T = res.eax
|
||||
|
||||
if max_leaf >= 0x0B:
|
||||
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
|
||||
num_threads: t.CUInt32T = res.ebx & 0xFFFF
|
||||
if num_threads > 0 and num_threads <= MAX_CPUS:
|
||||
return num_threads
|
||||
|
||||
cpu.cpuid(1, c.Addr(res))
|
||||
if res.edx & cpu.CPU_FEATURE_HTT:
|
||||
count: t.CUInt32T = (res.ebx >> 16) & 0xFF
|
||||
if count > 0 and count <= MAX_CPUS:
|
||||
return count
|
||||
return 1
|
||||
|
||||
def _wait_icr():
|
||||
timeout: t.CUInt32T = 1000000
|
||||
while timeout > 0:
|
||||
val: t.CUInt32T = read(LAPIC_ICR_LOW)
|
||||
if (val & (1 << 12)) == 0:
|
||||
return
|
||||
timeout -= 1
|
||||
|
||||
def _send_ipi(apic_id: t.CUInt32T, vector: t.CUInt32T, delivery_mode: t.CUInt32T):
|
||||
_wait_icr()
|
||||
write(LAPIC_ICR_HIGH, apic_id << 24)
|
||||
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
|
||||
_wait_icr()
|
||||
|
||||
def ap_entry():
|
||||
global _ap_ready
|
||||
my_id: t.CUInt32T = get_id()
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
|
||||
serial.puts(buf)
|
||||
_ap_ready = 1
|
||||
while True:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
|
||||
_trampoline_bin: t.CStatic | t.CArray[t.CUInt8T, 128] = [
|
||||
0xFA, # cli
|
||||
0x31, 0xC0, # xor ax, ax
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x83, 0xC8, 0x01, # or eax, 1
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
|
||||
|
||||
# 32-bit 保护模式开始
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x0F, 0x20, 0xE0, # mov eax, cr4
|
||||
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
|
||||
0x0F, 0x22, 0xE0, # mov cr4, eax
|
||||
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
|
||||
0x0F, 0x22, 0xD8, # mov cr3, eax
|
||||
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
|
||||
0x0F, 0x32, # rdmsr
|
||||
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
|
||||
0x0F, 0x79, # wrmsr
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
|
||||
|
||||
# 64-bit 长模式开始
|
||||
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
|
||||
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
|
||||
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x48, 0x8B, 0x04, 0x25, 0x28, 0x7F, 0x00, 0x00, # mov rax, [0x7F28]
|
||||
0xFF, 0xE0 # jmp rax
|
||||
]
|
||||
|
||||
def _setup_trampoline(entry_addr: t.CUInt64T, stack_addr: t.CUInt64T, cr3_val: t.CUInt64T):
|
||||
dest: t.CUInt8T | t.CPtr = t.CUInt8T(AP_TRAMPOLINE_ADDR, t.CPtr)
|
||||
src: t.CUInt8T | t.CPtr = c.Addr(_trampoline_bin)
|
||||
i: t.CInt
|
||||
for i in range(128):
|
||||
c.Set(c.Deref(dest + t.CUInt64T(i)), c.Deref(src + t.CUInt64T(i)))
|
||||
|
||||
gdt_ptr_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E00
|
||||
c.Set(c.Deref(t.CUInt16T(gdt_ptr_addr, t.CPtr)), t.CUInt16T(23))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_ptr_addr + 2, t.CPtr)), t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0E10))
|
||||
|
||||
gdt_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E10
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr, t.CPtr)), t.CUInt64T(0))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr + 8, t.CPtr)), t.CUInt64T(0x00AF9A000000FFFF))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr + 16, t.CPtr)), t.CUInt64T(0x00CF92000000FFFF))
|
||||
|
||||
c.Set(c.Deref(t.CUInt32T(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), t.CUInt32T(cr3_val))
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
|
||||
|
||||
gp_addr: t.CUInt64T = t.CUInt64T(c.Addr(gdt.gp))
|
||||
gdt_base: t.CUInt64T = c.Deref(t.CUInt64T(gp_addr + 2, t.CPtr))
|
||||
gdt_limit: t.CUInt16T = c.Deref(t.CUInt16T(gp_addr, t.CPtr))
|
||||
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
|
||||
|
||||
idt_addr: t.CUInt64T = t.CUInt64T(c.Addr(idt.idp))
|
||||
idt_base: t.CUInt64T = c.Deref(t.CUInt64T(idt_addr + 2, t.CPtr))
|
||||
idt_limit: t.CUInt16T = c.Deref(t.CUInt16T(idt_addr, t.CPtr))
|
||||
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
|
||||
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F28, t.CPtr)), entry_addr)
|
||||
|
||||
def start_aps():
|
||||
global _cpu_count, _ap_ready
|
||||
if _cpu_count <= 1: return
|
||||
|
||||
cr3_val: t.CUInt64T = 0
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
stack_size: t.CUInt64T = 8192
|
||||
i: t.CUInt32T
|
||||
for i in range(1, _cpu_count):
|
||||
_ap_ready = 0
|
||||
stack: t.CVoid | t.CPtr = mm.malloc(stack_size)
|
||||
if stack is None: continue
|
||||
stack_top: t.CUInt64T = t.CUInt64T(stack) + stack_size
|
||||
stack_top = stack_top & ~t.CUInt64T(15)
|
||||
|
||||
_setup_trampoline(t.CUInt64T(ap_entry), stack_top, cr3_val)
|
||||
|
||||
_send_ipi(i, 0, LAPIC_ICR_INIT)
|
||||
timer.timer_msleep(10)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
timer.timer_msleep(1)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
|
||||
wait: t.CUInt32T = 0
|
||||
while _ap_ready == 0 and wait < 5000:
|
||||
timer.timer_msleep(1)
|
||||
wait += 1
|
||||
|
||||
def early_init():
|
||||
global _cpu_count, _bsp_lapic_id
|
||||
features: t.CUInt32T = cpu.detect_features_static()
|
||||
if features & cpu.CPU_FEATURE_APIC:
|
||||
init()
|
||||
_cpu_count = detect_cpu_count()
|
||||
else:
|
||||
_cpu_count = 1
|
||||
|
||||
def get_cpu_count() -> t.CUInt32T:
|
||||
return _cpu_count
|
||||
|
||||
def get_lapic_id() -> t.CUInt32T:
|
||||
return get_id()
|
||||
346
VKernel/Kernel/drivers/core/cpu/cpu.py
Normal file
346
VKernel/Kernel/drivers/core/cpu/cpu.py
Normal file
@@ -0,0 +1,346 @@
|
||||
import fpu
|
||||
import asm
|
||||
import intr.gdt as gdt
|
||||
import string
|
||||
import t, c
|
||||
|
||||
IA32_KERNEL_GS_BASE: t.CDefine = 0xC0000102
|
||||
KERN_STACK_SIZE: t.CDefine = 8192
|
||||
|
||||
|
||||
CPU_FEATURE_FPU: t.CDefine = (1 << 0)
|
||||
CPU_FEATURE_PSE: t.CDefine = (1 << 1)
|
||||
CPU_FEATURE_MSR: t.CDefine = (1 << 2)
|
||||
CPU_FEATURE_PAE: t.CDefine = (1 << 3)
|
||||
CPU_FEATURE_MCE: t.CDefine = (1 << 4)
|
||||
CPU_FEATURE_CX8: t.CDefine = (1 << 5)
|
||||
CPU_FEATURE_APIC: t.CDefine = (1 << 6)
|
||||
CPU_FEATURE_SEP: t.CDefine = (1 << 7)
|
||||
CPU_FEATURE_MTRR: t.CDefine = (1 << 8)
|
||||
CPU_FEATURE_PGE: t.CDefine = (1 << 9)
|
||||
CPU_FEATURE_MCA: t.CDefine = (1 << 10)
|
||||
CPU_FEATURE_CMOV: t.CDefine = (1 << 11)
|
||||
CPU_FEATURE_PAT: t.CDefine = (1 << 12)
|
||||
CPU_FEATURE_PSE36: t.CDefine = (1 << 13)
|
||||
CPU_FEATURE_PSN: t.CDefine = (1 << 14)
|
||||
CPU_FEATURE_CLFSH: t.CDefine = (1 << 15)
|
||||
CPU_FEATURE_DS: t.CDefine = (1 << 16)
|
||||
CPU_FEATURE_ACPI: t.CDefine = (1 << 17)
|
||||
CPU_FEATURE_MMX: t.CDefine = (1 << 18)
|
||||
CPU_FEATURE_FXSR: t.CDefine = (1 << 19)
|
||||
CPU_FEATURE_SSE: t.CDefine = (1 << 20)
|
||||
CPU_FEATURE_SSE2: t.CDefine = (1 << 21)
|
||||
CPU_FEATURE_SS: t.CDefine = (1 << 22)
|
||||
CPU_FEATURE_HTT: t.CDefine = (1 << 23)
|
||||
CPU_FEATURE_TM: t.CDefine = (1 << 24)
|
||||
CPU_FEATURE_PBE: t.CDefine = (1 << 25)
|
||||
|
||||
class cpu_info(t.CStruct):
|
||||
vendor_id: t.CArray[t.CChar, 13]
|
||||
brand_string: t.CArray[t.CChar, 48]
|
||||
features: t.CUInt32T
|
||||
family: t.CUInt32T
|
||||
model: t.CUInt32T
|
||||
stepping: t.CUInt32T
|
||||
cpu_type: t.CUInt32T
|
||||
ext_model: t.CUInt32T
|
||||
ext_family: t.CUInt32T
|
||||
cpu_freq: t.CUInt64T
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class _tss:
|
||||
reserved0: t.CUInt64T
|
||||
rsp0: t.CUInt64T
|
||||
rsp1: t.CUInt64T
|
||||
rsp2: t.CUInt64T
|
||||
reserved1: t.CUInt64T
|
||||
ist1: t.CUInt64T
|
||||
ist2: t.CUInt64T
|
||||
ist3: t.CUInt64T
|
||||
ist4: t.CUInt64T
|
||||
ist5: t.CUInt64T
|
||||
ist6: t.CUInt64T
|
||||
ist7: t.CUInt64T
|
||||
reserved2: t.CUInt64T
|
||||
reserved3: t.CUInt16T
|
||||
io_map_base: t.CUInt16T
|
||||
|
||||
class cpuid_result(t.CStruct):
|
||||
eax: t.CUInt32T
|
||||
ebx: t.CUInt32T
|
||||
ecx: t.CUInt32T
|
||||
edx: t.CUInt32T
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _rdmsr_naked():
|
||||
c.Asm(f"""rdmsr
|
||||
shl rdx, 32
|
||||
or rax, rdx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _wrmsr_naked():
|
||||
# msr_write sets ecx=msr, r8=value. wrmsr needs ECX=msr, EDX:EAX=value.
|
||||
# Old code did `mov rax,rcx` (rax=msr) which wrote (value>>32):msr to MSR,
|
||||
# corrupting IA32_KERNEL_GS_BASE -> swapgs -> #GP on gs:[0]. Fixed below.
|
||||
c.Asm(f"""mov rax, r8
|
||||
mov rdx, r8
|
||||
shr rdx, 32
|
||||
wrmsr
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
def msr_read(msr: t.CUInt32T) -> t.CUInt64T:
|
||||
result: t.CUInt64T = 0
|
||||
func: t.CVoid | t.CPtr = _rdmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}
|
||||
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return result
|
||||
|
||||
def msr_write(msr: t.CUInt32T, value: t.CUInt64T):
|
||||
func: t.CVoid | t.CPtr = _wrmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _cpuid_naked():
|
||||
c.Asm(f"""push rbx
|
||||
mov eax, ecx
|
||||
cpuid
|
||||
mov dword ptr [rdx], eax
|
||||
mov dword ptr [rdx + 4], ebx
|
||||
mov dword ptr [rdx + 8], ecx
|
||||
mov dword ptr [rdx + 12], edx
|
||||
pop rbx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _cpuid_sub_naked():
|
||||
c.Asm(f"""push rbx
|
||||
mov eax, ecx
|
||||
mov ecx, r8d
|
||||
cpuid
|
||||
mov dword ptr [rdx], eax
|
||||
mov dword ptr [rdx + 4], ebx
|
||||
mov dword ptr [rdx + 8], ecx
|
||||
mov dword ptr [rdx + 12], edx
|
||||
pop rbx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_sub_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8d, {c.AsmInp(sub, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_features_static() -> t.CUInt32T:
|
||||
features: t.CUInt32T = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
|
||||
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
|
||||
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
|
||||
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
|
||||
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
|
||||
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
|
||||
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
|
||||
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
|
||||
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
|
||||
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
|
||||
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
|
||||
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
|
||||
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
|
||||
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
|
||||
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
|
||||
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
|
||||
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
|
||||
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
|
||||
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
|
||||
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
|
||||
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
|
||||
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
|
||||
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
|
||||
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
|
||||
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
|
||||
return features
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class per_cpu_data:
|
||||
user_rsp: t.CUInt64T
|
||||
kernel_rsp0: t.CUInt64T
|
||||
current_pid: t.CInt
|
||||
_pad0: t.CUInt32T
|
||||
_pad1: t.CUInt64T
|
||||
|
||||
_per_cpu: per_cpu_data
|
||||
|
||||
@t.Object
|
||||
class _CPUObject:
|
||||
tss: _tss
|
||||
features: t.CUInt32T
|
||||
def __init__(self):
|
||||
self.__init_tss__()
|
||||
|
||||
def __init_tss__(self):
|
||||
global _per_cpu
|
||||
string.memset(c.Addr(self.tss), 0, self.tss.__sizeof__())
|
||||
self.tss.io_map_base = self.tss.__sizeof__()
|
||||
string.memset(c.Addr(_per_cpu), 0, per_cpu_data.__sizeof__())
|
||||
gdt.setTSS64(5, t.CUInt64T(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
|
||||
gdt.flush()
|
||||
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
|
||||
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
|
||||
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
|
||||
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
|
||||
msr_write(IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(_per_cpu)))
|
||||
|
||||
def getInfo(self, info: cpu_info | t.CPtr):
|
||||
if not info: return
|
||||
res: cpuid_result
|
||||
cpuid(0, c.Addr(res))
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[0] = res.ebx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[1] = res.edx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[2] = res.ecx
|
||||
info.vendor_id[12] = '\0'
|
||||
info.features = self.detectFeatures()
|
||||
cpuid(1, c.Addr(res))
|
||||
info.stepping = (res.eax >> 0) & 0x0F
|
||||
info.model = (res.eax >> 4) & 0x0F
|
||||
info.family = (res.eax >> 8) & 0x0F
|
||||
info.cpu_type = (res.eax >> 12) & 0x03
|
||||
info.ext_model = (res.eax >> 16) & 0x0F
|
||||
info.ext_family = (res.eax >> 20) & 0xFF
|
||||
for i in range(4):
|
||||
cpuid(0x80000002 + i, c.Addr(res))
|
||||
base: t.CUInt32T | t.CPtr = t.CUInt32T(info.brand_string, t.CPtr)
|
||||
base[i * 4 + 0] = res.eax
|
||||
base[i * 4 + 1] = res.ebx
|
||||
base[i * 4 + 2] = res.ecx
|
||||
base[i * 4 + 3] = res.edx
|
||||
info.brand_string[47] = '\0'
|
||||
info.cpu_freq = 2000000000
|
||||
|
||||
def detectFeatures(self) -> t.CUInt32T:
|
||||
features: t.CInt32T = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
|
||||
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
|
||||
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
|
||||
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
|
||||
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
|
||||
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
|
||||
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
|
||||
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
|
||||
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
|
||||
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
|
||||
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
|
||||
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
|
||||
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
|
||||
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
|
||||
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
|
||||
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
|
||||
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
|
||||
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
|
||||
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
|
||||
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
|
||||
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
|
||||
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
|
||||
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
|
||||
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
|
||||
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
|
||||
return features
|
||||
|
||||
def enableInterrupts(self):
|
||||
c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def disableInterrupts(self):
|
||||
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def enableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
asm.outb(0x70, current & 0x7F)
|
||||
|
||||
def disableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
asm.outb(0x70, current | 0x80)
|
||||
|
||||
def readCR0(self) -> t.CUInt64T:
|
||||
cr0: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr0
|
||||
mov {c.AsmOut(cr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr0
|
||||
|
||||
def writeCR0(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr0, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR3(self) -> t.CUInt64T:
|
||||
cr3: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr3
|
||||
|
||||
def writeCR3(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr3, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR4(self) -> t.CUInt64T:
|
||||
cr4: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr4
|
||||
mov {c.AsmOut(cr4, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr4
|
||||
|
||||
def writeCR4(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr4, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readMSR(self, msr: t.CUInt32T) -> t.CUInt64T:
|
||||
return msr_read(msr)
|
||||
|
||||
def writeMSR(self, msr: t.CUInt32T, value: t.CUInt64T):
|
||||
msr_write(msr, value)
|
||||
|
||||
def setTSSRSP0(self, rsp0: t.CUInt64T):
|
||||
global _per_cpu
|
||||
self.tss.rsp0 = rsp0
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
|
||||
def set_kernel_rsp0(rsp0: t.CUInt64T):
|
||||
global _per_cpu
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
50
VKernel/Kernel/drivers/core/cpu/fpu.py
Normal file
50
VKernel/Kernel/drivers/core/cpu/fpu.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import cpu
|
||||
import t, c
|
||||
|
||||
|
||||
# FPU上下文结构体
|
||||
@c.Attribute(t.attr.aligned(16))
|
||||
class fpu_context:
|
||||
data: t.CUInt8T[512] # FXSAVE区域大小
|
||||
|
||||
|
||||
@t.Object
|
||||
class _FPUObject:
|
||||
CPUObject: cpu._CPUObject | t.CPtr
|
||||
# 初始化FPU
|
||||
def __init__(self, CPUObject: cpu._CPUObject | t.CPtr):
|
||||
self.enable()
|
||||
self.CPUObject = CPUObject
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 启用FPU
|
||||
def enable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
# 清除EM位(禁用仿真),设置MP位(监控协处理器)
|
||||
cr0 &= ~(1 << 2); # 清除EM位
|
||||
cr0 |= (1 << 1); # 设置MP位
|
||||
# 写入CR0寄存器
|
||||
self.CPUObject.writeCR0(cr0)
|
||||
# 读取CR4寄存器
|
||||
cr4: t.CUInt64T = self.CPUObject.readCR4()
|
||||
# 设置OSFXSR位和OSXMMEXCPT位,启用SSE
|
||||
cr4 |= (1 << 9) | (1 << 10)
|
||||
# 写入CR4寄存器
|
||||
self.CPUObject.writeCR4(cr4)
|
||||
# 初始化FPU
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 禁用FPU
|
||||
def disable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
# 设置EM位(启用仿真),清除MP位(禁用监控协处理器)
|
||||
cr0 |= (1 << 2) # 设置EM位
|
||||
cr0 &= ~(1 << 1) # 清除MP位
|
||||
# 写入CR0寄存器
|
||||
self.CPUObject.writeCR0(cr0)
|
||||
# 保存FPU上下文
|
||||
def save_context(self, context: fpu_context | t.CPtr):
|
||||
# 保存FPU状态到内存
|
||||
c.Asm(f"fxsave [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 恢复FPU上下文
|
||||
def restore_context(self, context: t.CConst | fpu_context | t.CPtr):
|
||||
# 从内存恢复FPU状态
|
||||
c.Asm(f"fxrstor [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
491
VKernel/Kernel/drivers/devfs/devfs.py
Normal file
491
VKernel/Kernel/drivers/devfs/devfs.py
Normal file
@@ -0,0 +1,491 @@
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperstring as string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_FILE_DESCRIPTORS: t.CDefine = 64
|
||||
MAX_DEVICE_FILES: t.CDefine = 32
|
||||
MAX_DIRECTORIES: t.CDefine = 16
|
||||
PATH_BUFFER_SIZE: t.CDefine = 256
|
||||
|
||||
directories: t.CArray[devfs_directory, MAX_DIRECTORIES] = [0]
|
||||
directory_count: t.CStatic | t.CInt = 0
|
||||
|
||||
files: t.CArray[devfs_file, MAX_DEVICE_FILES] = [0]
|
||||
file_count: t.CStatic | t.CInt = 0
|
||||
|
||||
|
||||
class _fd_table:
|
||||
file: devfs_file | t.CPtr
|
||||
flags: t.CInt
|
||||
|
||||
fd_table: t.CArray[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
|
||||
|
||||
@t.Object
|
||||
class devfs_directory:
|
||||
name: t.CArray[t.CChar, 64]
|
||||
parent: 'devfs_directory' | t.CPtr
|
||||
|
||||
@staticmethod
|
||||
def find(path: t.CConst | str,
|
||||
root_directory: devfs_directory | t.CPtr) -> devfs_directory | t.CPtr:
|
||||
if not path or string.strchr(path, '/') != path: return None
|
||||
if not root_directory: return None
|
||||
|
||||
current_dir: devfs_directory | t.CPtr = root_directory
|
||||
result: t.CArray[str, PATH_BUFFER_SIZE]
|
||||
token = string.split(path, "/", result)
|
||||
|
||||
for i in result:
|
||||
found: bool = False
|
||||
for d in range(directory_count):
|
||||
dirp: devfs_directory = c.Addr(directories[d])
|
||||
if dirp.parent == current_dir and string.samestr(dirp.name, i):
|
||||
current_dir = dirp
|
||||
found = True
|
||||
break
|
||||
if not found: return None
|
||||
|
||||
return current_dir
|
||||
|
||||
@staticmethod
|
||||
def find_child(name: t.CConst | str,
|
||||
parent: devfs_directory | t.CPtr) -> devfs_directory | t.CPtr:
|
||||
for d in range(directory_count):
|
||||
dirp: devfs_directory = c.Addr(directories[d])
|
||||
if dirp.parent == parent and string.samestr(dirp.name, name):
|
||||
return dirp
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def list_subdirs(dir_ptr: devfs_directory | t.CPtr,
|
||||
buffer: str,
|
||||
size: t.CUInt32T,
|
||||
pos: t.CInt) -> t.CInt:
|
||||
for d in range(directory_count):
|
||||
dirp: devfs_directory = c.Addr(directories[d])
|
||||
if dirp.parent == dir_ptr:
|
||||
name_len: t.CInt = string.strlen(dirp.name)
|
||||
if pos + name_len + 1 > size:
|
||||
break
|
||||
string.strcpy(buffer + pos, dirp.name)
|
||||
pos += name_len
|
||||
buffer[pos] = '\n'
|
||||
pos += 1
|
||||
return pos
|
||||
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class devfs_file:
|
||||
name: t.CArray[t.CChar, 64]
|
||||
private_data: t.CVoid | t.CPtr
|
||||
parent_dir: 'devfs_directory' | t.CPtr
|
||||
|
||||
@staticmethod
|
||||
def find_in_dir(file_name: t.CConst | str,
|
||||
dir_ptr: devfs_directory | t.CPtr) -> devfs_file | t.CPtr:
|
||||
for f in range(file_count):
|
||||
fp: devfs_file | t.CPtr = c.Addr(files[f])
|
||||
if fp.parent_dir == dir_ptr and string.samestr(fp.name, file_name):
|
||||
return fp
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def list_in_dir(dir_ptr: devfs_directory | t.CPtr,
|
||||
buffer: str,
|
||||
size: t.CUInt32T,
|
||||
pos: t.CInt) -> t.CInt:
|
||||
for f in range(file_count):
|
||||
filep: devfs_file | t.CPtr = c.Addr(files[f])
|
||||
if filep.parent_dir == dir_ptr:
|
||||
name_len: t.CInt = string.strlen(filep.name)
|
||||
if pos + name_len + 1 > size:
|
||||
break
|
||||
string.strcpy(buffer + pos, filep.name)
|
||||
pos += name_len
|
||||
buffer[pos] = '\n'
|
||||
pos += 1
|
||||
return pos
|
||||
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return 0
|
||||
|
||||
@t.Object
|
||||
class _DevFSObject:
|
||||
root_directory: devfs_directory | t.CPtr
|
||||
|
||||
def __init__(self):
|
||||
global directory_count, file_count
|
||||
self.root_directory = None
|
||||
directory_count = 0
|
||||
file_count = 0
|
||||
string.memset(c.Addr(directories), 0, devfs_directory.__sizeof__() * MAX_DIRECTORIES)
|
||||
string.memset(c.Addr(files), 0, devfs_file.__sizeof__() * MAX_DEVICE_FILES)
|
||||
string.memset(c.Addr(fd_table), 0, _fd_table.__sizeof__() * MAX_FILE_DESCRIPTORS)
|
||||
|
||||
def create_single_dir(self, parent: devfs_directory | t.CPtr,
|
||||
dir_name: t.CConst | str) -> devfs_directory | t.CPtr:
|
||||
global directory_count
|
||||
if not parent or not dir_name: return None
|
||||
if directory_count >= MAX_DIRECTORIES: return None
|
||||
if string.strlen(dir_name) >= 64: return None
|
||||
|
||||
new_dir: devfs_directory | t.CPtr = c.Addr(directories[directory_count])
|
||||
directory_count += 1
|
||||
|
||||
string.strcpy(new_dir.name, dir_name)
|
||||
new_dir.parent = parent
|
||||
|
||||
return new_dir
|
||||
|
||||
def find_or_create_directory(self, path: t.CConst | str) -> devfs_directory | t.CPtr:
|
||||
global directory_count
|
||||
if not path or string.samestr(path, "/"): return None
|
||||
|
||||
serial.puts("A")
|
||||
if not self.root_directory:
|
||||
self.root_directory = c.Addr(directories[directory_count])
|
||||
directory_count += 1
|
||||
string.strcpy(self.root_directory.name, "")
|
||||
self.root_directory.parent = None
|
||||
|
||||
serial.puts("B")
|
||||
current: devfs_directory | t.CPtr = self.root_directory
|
||||
buf: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
|
||||
buf_idx: t.CInt = 0
|
||||
p: t.CInt = 0
|
||||
if path[p] == '/':
|
||||
p += 1
|
||||
serial.puts("C")
|
||||
while path[p] != '\0':
|
||||
if path[p] == '/':
|
||||
if buf_idx > 0:
|
||||
found_child: devfs_directory | t.CPtr = devfs_directory.find_child(buf, current)
|
||||
if not found_child:
|
||||
found_child = self.create_single_dir(current, buf)
|
||||
if not found_child: return None
|
||||
current = found_child
|
||||
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
|
||||
buf_idx = 0
|
||||
p += 1
|
||||
else:
|
||||
buf[buf_idx] = path[p]
|
||||
buf_idx += 1
|
||||
p += 1
|
||||
serial.puts("D")
|
||||
if buf_idx > 0:
|
||||
found_child: devfs_directory | t.CPtr = devfs_directory.find_child(buf, current)
|
||||
if not found_child:
|
||||
found_child = self.create_single_dir(current, buf)
|
||||
if not found_child: return None
|
||||
current = found_child
|
||||
serial.puts("E")
|
||||
|
||||
return current
|
||||
|
||||
def init(self) -> t.CInt:
|
||||
self.create_directory("/dev")
|
||||
self.create_directory("/dev/input")
|
||||
return 0
|
||||
|
||||
def create_directory(self, path: t.CConst | str) -> t.CInt:
|
||||
serial.puts("T1")
|
||||
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
|
||||
serial.puts("T2")
|
||||
return 0 if dir_ptr else -1
|
||||
|
||||
def create_file(self, path: t.CConst | str,
|
||||
file_ptr: devfs_file | t.CPtr,
|
||||
private_data: t.CVoid | t.CPtr) -> t.CInt:
|
||||
global file_count
|
||||
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
|
||||
string.strcpy(path_copy, path)
|
||||
|
||||
last_slash: str | t.CPtr = string.strrchr(path_copy, '/')
|
||||
|
||||
if not last_slash: return -1
|
||||
|
||||
last_slash[0] = '\0'
|
||||
dir_path = path_copy
|
||||
file_name: str | t.CPtr = last_slash + 1
|
||||
|
||||
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(dir_path)
|
||||
if not dir_ptr: return -1
|
||||
|
||||
if devfs_file.find_in_dir(file_name, dir_ptr):
|
||||
return -1
|
||||
|
||||
if file_count >= MAX_DEVICE_FILES: return -1
|
||||
|
||||
if file_ptr:
|
||||
string.strcpy(file_ptr.name, file_name)
|
||||
file_ptr.private_data = private_data
|
||||
file_ptr.parent_dir = dir_ptr
|
||||
files[file_count] = file_ptr
|
||||
else:
|
||||
new_file: devfs_file | t.CPtr = c.Addr(files[file_count])
|
||||
string.strcpy(new_file.name, file_name)
|
||||
new_file.private_data = private_data
|
||||
new_file.parent_dir = dir_ptr
|
||||
|
||||
file_count += 1
|
||||
return 0
|
||||
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
|
||||
string.strcpy(path_copy, path)
|
||||
|
||||
last_slash: str | t.CPtr = string.strrchr(path_copy, '/')
|
||||
|
||||
if not last_slash: return -1
|
||||
|
||||
last_slash[0] = '\0'
|
||||
dir_path = path_copy
|
||||
file_name: str | t.CPtr = last_slash + 1
|
||||
|
||||
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(dir_path, self.root_directory)
|
||||
if not dir_ptr: return -1
|
||||
|
||||
file_ptr: devfs_file | t.CPtr = devfs_file.find_in_dir(file_name, dir_ptr)
|
||||
if not file_ptr: return -1
|
||||
|
||||
fd: t.CInt = -1
|
||||
for i in range(MAX_FILE_DESCRIPTORS):
|
||||
if not fd_table[i].file:
|
||||
fd = i
|
||||
break
|
||||
|
||||
if fd == -1: return -1
|
||||
|
||||
ret: t.CInt = file_ptr.open(path, flags)
|
||||
if ret != 0: return ret
|
||||
|
||||
fd_table[fd].file = file_ptr
|
||||
fd_table[fd].flags = flags
|
||||
return fd
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
file_ptr.close(fd)
|
||||
fd_table[fd].file = None
|
||||
fd_table[fd].flags = 0
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
return file_ptr.read(fd, buffer, size)
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
return file_ptr.write(fd, buffer, size)
|
||||
|
||||
def ioctl(self, fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
return file_ptr.ioctl(fd, cmd, arg)
|
||||
|
||||
def list_directory(self, path: t.CConst | str,
|
||||
buffer: str,
|
||||
size: t.CUInt32T) -> t.CInt:
|
||||
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(path, self.root_directory)
|
||||
if not dir_ptr or not buffer or size == 0: return -1
|
||||
|
||||
pos: t.CInt = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
|
||||
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
|
||||
|
||||
return pos
|
||||
|
||||
DevFSObject: _DevFSObject | t.CPtr
|
||||
_DevFSObject_instance: _DevFSObject
|
||||
|
||||
|
||||
def devfs_init() -> t.CInt:
|
||||
global DevFSObject, _DevFSObject_instance
|
||||
DevFSObject = c.Addr(_DevFSObject_instance)
|
||||
_DevFSObject_instance = _DevFSObject()
|
||||
# _DevFSObject_instance.__init__()
|
||||
DevFSObject.init()
|
||||
return 0
|
||||
|
||||
def devfs_create_directory(path: t.CConst | str) -> t.CInt:
|
||||
return DevFSObject.create_directory(path)
|
||||
|
||||
def devfs_create_file(path: t.CConst | str,
|
||||
file_ptr: devfs_file | t.CPtr,
|
||||
private_data: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return DevFSObject.create_file(path, file_ptr, private_data)
|
||||
|
||||
def devfs_open(path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
return DevFSObject.open(path, flags)
|
||||
|
||||
def devfs_close(fd: t.CInt) -> t.CInt:
|
||||
return DevFSObject.close(fd)
|
||||
|
||||
def devfs_read(fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return DevFSObject.read(fd, buffer, size)
|
||||
|
||||
def devfs_write(fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return DevFSObject.write(fd, buffer, size)
|
||||
|
||||
def devfs_ioctl(fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return DevFSObject.ioctl(fd, cmd, arg)
|
||||
|
||||
def devfs_list_directory(path: t.CConst | str,
|
||||
buffer: str,
|
||||
size: t.CUInt32T) -> t.CInt:
|
||||
return DevFSObject.list_directory(path, buffer, size)
|
||||
|
||||
serial0_file: devfs_file
|
||||
|
||||
def serial0_open(self: t.CVoid | t.CPtr, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
serial.puts("[serial0] open: ")
|
||||
serial.puts(path)
|
||||
serial.puts("\n")
|
||||
return 0
|
||||
|
||||
def serial0_close(self: t.CVoid | t.CPtr, fd: t.CInt) -> t.CInt:
|
||||
serial.puts("[serial0] close\n")
|
||||
return 0
|
||||
|
||||
def serial0_read(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
serial.puts("[serial0] read\n")
|
||||
return 0
|
||||
|
||||
def serial0_write(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
serial.puts("[serial0] write\n")
|
||||
serial.puts(str(buffer))
|
||||
serial.puts("\n")
|
||||
return size
|
||||
|
||||
def devfs_register_serial0() -> t.CInt:
|
||||
global serial0_file
|
||||
serial0_file = devfs_file()
|
||||
serial0_file.open = serial0_open
|
||||
serial0_file.close = serial0_close
|
||||
serial0_file.read = serial0_read
|
||||
serial0_file.write = serial0_write
|
||||
return devfs_create_file("/dev/serial0", serial0_file, None)
|
||||
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class serial1_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
serial.puts("[serial1] open: ")
|
||||
serial.puts(path)
|
||||
serial.puts("\n")
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
serial.puts("[serial1] close\n")
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
serial.puts("[serial1] read\n")
|
||||
return 0
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
serial.puts("[serial1] write\n")
|
||||
serial.puts(str(buffer))
|
||||
serial.puts("\n")
|
||||
return size
|
||||
|
||||
serial1_file: serial1_device
|
||||
|
||||
def devfs_register_serial1() -> t.CInt:
|
||||
global serial1_file
|
||||
serial1_file = serial1_device()
|
||||
return devfs_create_file("/dev/serial1", serial1_file, None)
|
||||
|
||||
import drivers.input.keyboard.keyboard as keyboard
|
||||
import drivers.input.mouse.mouse as mouse
|
||||
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class keyboard_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
count: t.CUInt32T = 0
|
||||
while count < size and keyboard.has_data():
|
||||
sc: t.CUInt8T = keyboard.read_scancode()
|
||||
ch: t.CChar = keyboard.scancode_to_ascii(sc)
|
||||
if ch != '\0':
|
||||
c.Set(t.CChar(buffer, t.CPtr)[count], ch)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return -1
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return 0
|
||||
|
||||
kbd_file: keyboard_device
|
||||
|
||||
def devfs_register_keyboard() -> t.CInt:
|
||||
global kbd_file
|
||||
kbd_file = keyboard_device()
|
||||
keyboard.init()
|
||||
return devfs_create_file("/dev/input/keyboard", kbd_file, None)
|
||||
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class mouse_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
if not mouse.has_data(): return 0
|
||||
pkt: mouse.mouse_packet
|
||||
mouse.read_packet(c.Addr(pkt))
|
||||
if size >= 1:
|
||||
c.Set(t.CUInt8T(buffer, t.CPtr)[0], pkt.buttons)
|
||||
if size >= 5:
|
||||
buf: t.CUInt32T | t.CPtr = t.CVoid(t.CUInt64T(buffer) + 1, t.CPtr)
|
||||
c.Set(t.CInt32T(buf, t.CPtr)[0], mouse.get_x())
|
||||
c.Set(t.CInt32T(buf, t.CPtr)[1], mouse.get_y())
|
||||
return 5
|
||||
return 1
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
return -1
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return 0
|
||||
|
||||
mse_file: mouse_device
|
||||
|
||||
def devfs_register_mouse() -> t.CInt:
|
||||
global mse_file
|
||||
mse_file = mouse_device()
|
||||
mouse.init()
|
||||
return devfs_create_file("/dev/input/mouse", mse_file, None)
|
||||
237
VKernel/Kernel/drivers/fs/fat32/example_fs.py
Normal file
237
VKernel/Kernel/drivers/fs/fat32/example_fs.py
Normal file
@@ -0,0 +1,237 @@
|
||||
from stdint import *
|
||||
import fat32 as fs
|
||||
import fat32_types as types
|
||||
import fat32_part as part
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import t, c
|
||||
|
||||
|
||||
def print_fresult(res: types.FRESULT, msg: t.CConst) -> t.CInt:
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f"[成功] {msg}")
|
||||
return 0
|
||||
else:
|
||||
print(f"[失败] {msg}: {res}")
|
||||
return -1
|
||||
|
||||
|
||||
def print_fresult_void(res: types.FRESULT, msg: t.CConst):
|
||||
print_fresult(res, msg)
|
||||
|
||||
|
||||
def example_main() -> t.CInt:
|
||||
print("=== FAT32 文件系统完整示例 ===")
|
||||
print()
|
||||
|
||||
# 1. 扫描可用驱动器
|
||||
print("--- 1. 扫描可用驱动器 ---")
|
||||
res: types.FRESULT = fs.scan_drives()
|
||||
print_fresult_void(res, "扫描驱动器")
|
||||
|
||||
drive_count: t.CInt = fs.get_drive_count()
|
||||
print(f"找到 {drive_count} 个驱动器")
|
||||
i: t.CInt
|
||||
for i in range(drive_count):
|
||||
letter: t.CChar = fs.get_drive_letter(i)
|
||||
part_count: t.CInt = fs.get_partition_count(letter)
|
||||
print(f" 驱动器 {i}: {letter}")
|
||||
for j in range(part_count):
|
||||
is_fat32: t.CInt = fs.is_partition_fat32(letter, j)
|
||||
print(f" 分区 {j}: FAT32={is_fat32}")
|
||||
print()
|
||||
|
||||
# 2. 挂载文件系统
|
||||
print("--- 2. 挂载文件系统 ---")
|
||||
res = fs.mount()
|
||||
if print_fresult(res, "挂载文件系统") != 0:
|
||||
print("提示: 可能需要先格式化磁盘")
|
||||
print()
|
||||
|
||||
# 3. 文件系统信息
|
||||
print("--- 3. 文件系统信息 ---")
|
||||
mounted: t.CInt = fs.is_mounted()
|
||||
print(f"已挂载: {mounted}")
|
||||
if mounted:
|
||||
total_clusters: t.CUInt32T = fs.get_total()
|
||||
free_clusters: t.CUInt32T = fs.get_free()
|
||||
cluster_size: t.CUInt32T = fs.get_cluster_size()
|
||||
total_bytes: t.CUInt64T = t.CUInt64T(total_clusters) * t.CUInt64T(cluster_size)
|
||||
free_bytes: t.CUInt64T = t.CUInt64T(free_clusters) * t.CUInt64T(cluster_size)
|
||||
print(f"总簇数: {total_clusters}")
|
||||
print(f"空闲簇数: {free_clusters}")
|
||||
print(f"簇大小: {cluster_size} 字节")
|
||||
print(f"总大小: {total_bytes} 字节")
|
||||
print(f"空闲大小: {free_bytes} 字节")
|
||||
print()
|
||||
|
||||
# 4. 元数据操作
|
||||
print("--- 4. 元数据操作 ---")
|
||||
fs.set_metadata(0x12345678)
|
||||
metadata: t.CUInt32T = fs.get_metadata()
|
||||
print(f"设置的元数据: 0x{metadata:08X}")
|
||||
print()
|
||||
|
||||
# 5. 获取 FAT 时间
|
||||
print("--- 5. 获取 FAT 时间 ---")
|
||||
fattime: t.CUInt32T = fs.get_fattime()
|
||||
print(f"当前 FAT 时间: 0x{fattime:08X}")
|
||||
print()
|
||||
|
||||
# 6. 目录操作
|
||||
if fs.is_mounted():
|
||||
print("--- 6. 目录操作 ---")
|
||||
|
||||
# 创建目录
|
||||
res = fs.mkdir("/test_dir_1")
|
||||
print_fresult_void(res, "创建目录 /test_dir_1")
|
||||
|
||||
res = fs.mkdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
|
||||
|
||||
res = fs.mkdir("/test_dir_2")
|
||||
print_fresult_void(res, "创建目录 /test_dir_2")
|
||||
print()
|
||||
|
||||
# 7. 文件操作
|
||||
print("--- 7. 文件操作 ---")
|
||||
|
||||
# 创建并写入文件
|
||||
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp1 is not None:
|
||||
test_data1: t.CConst = "Hello, World!"
|
||||
written: t.CUInt32T = fs.write(fp1, test_data1, 13)
|
||||
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
|
||||
fs.close(fp1)
|
||||
|
||||
# 打开追加
|
||||
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
|
||||
if fp2 is not None:
|
||||
test_data2: t.CConst = " Append data!"
|
||||
written2: t.CUInt32T = fs.write(fp2, test_data2, 13)
|
||||
print(f"追加写入: {written2} 字节")
|
||||
fs.close(fp2)
|
||||
|
||||
# 读取文件
|
||||
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
|
||||
if fp3 is not None:
|
||||
buf: t.CArray[t.CUInt8T, 256]
|
||||
read_bytes: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"读取字节数: {read_bytes}")
|
||||
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# seek 和 tell
|
||||
fs.seek(fp3, 5)
|
||||
pos: t.CUInt32T = fs.tell(fp3)
|
||||
print(f"seek 到位置 5, 当前位置: {pos}")
|
||||
|
||||
read_bytes2: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# 获取文件大小
|
||||
fsize: t.CUInt32T = fs.size(fp3)
|
||||
print(f"文件大小: {fsize} 字节")
|
||||
|
||||
fs.close(fp3)
|
||||
|
||||
# 创建另一个文件
|
||||
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp4 is not None:
|
||||
large_data: t.CArray[t.CUInt8T, 1024]
|
||||
k: t.CInt
|
||||
for k in range(1024):
|
||||
large_data[k] = t.CUInt8T(ord('A') + (k % 26))
|
||||
written3: t.CUInt32T = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
|
||||
print(f"创建大文件, 写入: {written3} 字节")
|
||||
fs.close(fp4)
|
||||
print()
|
||||
|
||||
# 8. 文件状态和属性
|
||||
print("--- 8. 文件状态和属性 ---")
|
||||
|
||||
info: types.fileinfo
|
||||
res = fs.stat("/test_dir_1/file1.txt", info)
|
||||
print_fresult_void(res, "获取文件信息")
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f" 文件名: {info.fname}")
|
||||
print(f" 大小: {info.file_size} 字节")
|
||||
print(f" 属性: 0x{info.attr:02X}")
|
||||
print(f" 创建时间: 0x{info.ctime:04X}")
|
||||
print(f" 创建日期: 0x{info.cdate:04X}")
|
||||
print(f" 修改时间: 0x{info.mtime:04X}")
|
||||
print(f" 修改日期: 0x{info.mdate:04X}")
|
||||
print(f" 访问日期: 0x{info.adate:04X}")
|
||||
|
||||
# 修改属性
|
||||
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
|
||||
print_fresult_void(res, "设置文件为只读")
|
||||
print()
|
||||
|
||||
# 9. 重命名和移动
|
||||
print("--- 9. 重命名和移动 ---")
|
||||
|
||||
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
|
||||
print_fresult_void(res, "重命名文件")
|
||||
|
||||
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
|
||||
print_fresult_void(res, "移动文件")
|
||||
|
||||
res = fs.rename("/test_dir_2", "/test_dir_renamed")
|
||||
print_fresult_void(res, "重命名目录")
|
||||
print()
|
||||
|
||||
# 10. 列出目录
|
||||
print("--- 10. 列出目录 ---")
|
||||
|
||||
dp: types.dirobj
|
||||
res = fs.opendir("/", dp)
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print("根目录内容:")
|
||||
dir_info: types.fileinfo
|
||||
while True:
|
||||
res = fs.readdir(dp, dir_info)
|
||||
if res != types.FRESULT.FR_OK:
|
||||
break
|
||||
attr_str: t.CConst = ""
|
||||
if dir_info.attr & types.AM_DIR:
|
||||
attr_str = attr_str + "D"
|
||||
else:
|
||||
attr_str = attr_str + "F"
|
||||
if dir_info.attr & types.AM_RDO:
|
||||
attr_str = attr_str + "R"
|
||||
if dir_info.attr & types.AM_HID:
|
||||
attr_str = attr_str + "H"
|
||||
if dir_info.attr & types.AM_SYS:
|
||||
attr_str = attr_str + "S"
|
||||
if dir_info.attr & types.AM_ARC:
|
||||
attr_str = attr_str + "A"
|
||||
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
|
||||
fs.closedir(dp)
|
||||
print()
|
||||
|
||||
# 11. 删除文件和目录
|
||||
print("--- 11. 删除文件和目录 ---")
|
||||
|
||||
res = fs.remove("/test_dir_renamed/moved.txt")
|
||||
print_fresult_void(res, "删除文件")
|
||||
|
||||
res = fs.remove("/test_dir_1/large_file.txt")
|
||||
print_fresult_void(res, "删除大文件")
|
||||
|
||||
res = fs.rmdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "删除子目录")
|
||||
|
||||
res = fs.rmdir("/test_dir_1")
|
||||
print_fresult_void(res, "删除目录 /test_dir_1")
|
||||
|
||||
res = fs.rmdir("/test_dir_renamed")
|
||||
print_fresult_void(res, "删除目录 /test_dir_renamed")
|
||||
print()
|
||||
|
||||
# 12. 卸载文件系统
|
||||
print("--- 12. 卸载文件系统 ---")
|
||||
res = fs.unmount()
|
||||
print_fresult_void(res, "卸载文件系统")
|
||||
print()
|
||||
|
||||
print("=== 示例完成 ===")
|
||||
return 0
|
||||
208
VKernel/Kernel/drivers/fs/fat32/fat32.py
Normal file
208
VKernel/Kernel/drivers/fs/fat32/fat32.py
Normal file
@@ -0,0 +1,208 @@
|
||||
from stdint import *
|
||||
import string
|
||||
import fat32_types as types
|
||||
import fat32_time as ftime
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import fat32_part as part
|
||||
import fat32_diskio as diskio
|
||||
import sched.sched as sched
|
||||
import t, c
|
||||
|
||||
|
||||
default_fs: types.volinfo = types.volinfo()
|
||||
_fs_lock: t.CInt = 0
|
||||
|
||||
def lock():
|
||||
global _fs_lock
|
||||
while True:
|
||||
c.Asm("cli")
|
||||
if _fs_lock == 0:
|
||||
_fs_lock = 1
|
||||
c.Asm("sti")
|
||||
return
|
||||
c.Asm("sti")
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def unlock():
|
||||
global _fs_lock
|
||||
_fs_lock = 0
|
||||
|
||||
def mount() -> types.FRESULT:
|
||||
default_fs.pdrv = 0
|
||||
default_fs.hidden_sectors = 0
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
|
||||
if dres == types.DRESULT.RES_OK:
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
default_fs.hidden_sectors = 0
|
||||
else:
|
||||
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
|
||||
if sig == 0xAA55:
|
||||
ptype: t.CUInt8T = buf[450]
|
||||
if ptype != 0:
|
||||
slba: t.CUInt32T = t.CUInt32T(buf[454]) | (t.CUInt32T(buf[455]) << 8) | (t.CUInt32T(buf[456]) << 16) | (t.CUInt32T(buf[457]) << 24)
|
||||
default_fs.hidden_sectors = slba
|
||||
if default_fs.mounted: return types.FRESULT.FR_OK
|
||||
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK:
|
||||
dsk_res = diskio.init(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
|
||||
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
|
||||
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
|
||||
wres: types.FRESULT = default_fs.win_read(0)
|
||||
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
|
||||
bps: t.CUInt16T = default_fs.win[11] | (t.CUInt16T(default_fs.win[12]) << 8)
|
||||
spc: t.CUInt8T = default_fs.win[13]
|
||||
rsc: t.CUInt16T = default_fs.win[14] | (t.CUInt16T(default_fs.win[15]) << 8)
|
||||
nf: t.CUInt8T = default_fs.win[16]
|
||||
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
root_ent: t.CUInt16T = default_fs.win[17] | (t.CUInt16T(default_fs.win[18]) << 8)
|
||||
fat16sz: t.CUInt16T = default_fs.win[22] | (t.CUInt16T(default_fs.win[23]) << 8)
|
||||
tot32: t.CUInt32T = t.CUInt32T(default_fs.win[32]) | (t.CUInt32T(default_fs.win[33]) << 8) | (t.CUInt32T(default_fs.win[34]) << 16) | (t.CUInt32T(default_fs.win[35]) << 24)
|
||||
fat32sz: t.CUInt32T = t.CUInt32T(default_fs.win[36]) | (t.CUInt32T(default_fs.win[37]) << 8) | (t.CUInt32T(default_fs.win[38]) << 16) | (t.CUInt32T(default_fs.win[39]) << 24)
|
||||
root_clus: t.CUInt32T = t.CUInt32T(default_fs.win[44]) | (t.CUInt32T(default_fs.win[45]) << 8) | (t.CUInt32T(default_fs.win[46]) << 16) | (t.CUInt32T(default_fs.win[47]) << 24)
|
||||
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
fsinfo_sec: t.CUInt16T = default_fs.win[48] | (t.CUInt16T(default_fs.win[49]) << 8)
|
||||
bkboot_sec: t.CUInt16T = default_fs.win[50] | (t.CUInt16T(default_fs.win[51]) << 8)
|
||||
default_fs.sector_size = 512
|
||||
default_fs.cluster_sectors = spc
|
||||
default_fs.cluster_size = t.CUInt32T(spc) * 512
|
||||
default_fs.num_fats = nf
|
||||
default_fs.reserved_sectors = rsc
|
||||
default_fs.fat_size = fat32sz
|
||||
default_fs.fat_start = t.CUInt64T(rsc)
|
||||
default_fs.total_sectors = t.CUInt64T(tot32)
|
||||
default_fs.root_cluster = root_clus
|
||||
default_fs.fsinfo_sector = fsinfo_sec
|
||||
default_fs.backup_sector = bkboot_sec
|
||||
default_fs.vol_id = t.CUInt32T(default_fs.win[67]) | (t.CUInt32T(default_fs.win[68]) << 8) | (t.CUInt32T(default_fs.win[69]) << 16) | (t.CUInt32T(default_fs.win[70]) << 24)
|
||||
data_sectors: t.CUInt64T = default_fs.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
|
||||
default_fs.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
|
||||
default_fs.data_start = default_fs.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
|
||||
default_fs.last_alloc = 2
|
||||
default_fs.free_clusters = 0xFFFFFFFF
|
||||
if fsinfo_sec != 0:
|
||||
default_fs.fsinfo_read()
|
||||
default_fs.mounted = 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def unmount() -> types.FRESULT:
|
||||
return default_fs.unmount()
|
||||
|
||||
def format(sec_per_clus: t.CUInt8T = 0, vol_id: t.CUInt32T = 0) -> types.FRESULT:
|
||||
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
|
||||
|
||||
def open(path: t.CConst | str, mode: t.CUInt8T) -> types.fileobj | t.CPtr:
|
||||
return default_fs.file_open(path, mode)
|
||||
|
||||
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.close()
|
||||
|
||||
def read(fp: types.fileobj | t.CPtr, buff: t.CVoid | t.CPtr, btr: t.CUInt32T) -> t.CUInt32T:
|
||||
br: t.CUInt32T = 0
|
||||
fp.read(buff, btr, c.Addr(br))
|
||||
return br
|
||||
|
||||
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T) -> t.CUInt32T:
|
||||
bw: t.CUInt32T = 0
|
||||
fp.write(buff, btw, c.Addr(bw))
|
||||
return bw
|
||||
|
||||
def seek(fp: types.fileobj | t.CPtr, offset: t.CUInt32T) -> types.FRESULT:
|
||||
return fp.seek(offset)
|
||||
|
||||
def tell(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
|
||||
return fp.tell()
|
||||
|
||||
def size(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
|
||||
return fp.size()
|
||||
|
||||
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.truncate()
|
||||
|
||||
def remove(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_delete(path)
|
||||
|
||||
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.file_stat(path, info)
|
||||
|
||||
def mkdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_make(path)
|
||||
|
||||
def rmdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_remove(path)
|
||||
|
||||
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_open_path(path, dp)
|
||||
|
||||
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_read(dp, info)
|
||||
|
||||
def closedir(dp: types.dirobj | t.CPtr):
|
||||
dp.is_open = 0
|
||||
|
||||
def chmod(path: t.CConst | str, attr: t.CUInt8T, mask: t.CUInt8T) -> types.FRESULT:
|
||||
return default_fs.chmod(path, attr, mask)
|
||||
|
||||
def utime(path: t.CConst | str, mtime: t.CUInt16T, mdate: t.CUInt16T) -> types.FRESULT:
|
||||
return default_fs.utime(path, mtime, mdate)
|
||||
|
||||
def get_free() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
if default_fs.free_clusters == 0xFFFFFFFF:
|
||||
return default_fs.count_free_clusters()
|
||||
return default_fs.free_clusters
|
||||
|
||||
def get_total() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.total_clusters
|
||||
|
||||
def get_cluster_size() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.cluster_size
|
||||
|
||||
def is_mounted() -> t.CInt:
|
||||
return default_fs.mounted
|
||||
|
||||
def last_error() -> t.CUInt32T:
|
||||
return default_fs.last_error
|
||||
|
||||
def get_fattime() -> t.CUInt32T:
|
||||
return ftime.get_fattime()
|
||||
|
||||
def get_metadata() -> t.CUInt32T:
|
||||
return default_fs.metadata
|
||||
|
||||
def set_metadata(val: t.CUInt32T):
|
||||
default_fs.metadata = val
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
return part.scan_drives()
|
||||
|
||||
def get_drive_count() -> t.CInt:
|
||||
return part.get_drive_count()
|
||||
|
||||
def get_drive_letter(idx: t.CInt) -> t.CChar:
|
||||
return part.get_drive_letter(idx)
|
||||
|
||||
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
|
||||
return part.set_drive_letter(idx, letter)
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> t.CInt:
|
||||
return part.get_partition_count(letter)
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
|
||||
return part.is_partition_fat32(letter, part_idx)
|
||||
|
||||
16
VKernel/Kernel/drivers/fs/fat32/fat32_core.py
Normal file
16
VKernel/Kernel/drivers/fs/fat32/fat32_core.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import t, c
|
||||
|
||||
|
||||
_read32 = types._read32
|
||||
_read16 = types._read16
|
||||
_write32 = types._write32
|
||||
_write16 = types._write16
|
||||
|
||||
|
||||
def is_eoc(cluster: t.CUInt32T) -> t.CInt:
|
||||
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
|
||||
|
||||
def is_free(cluster: t.CUInt32T) -> t.CInt:
|
||||
return 1 if cluster == types.CLUSTER_FREE else 0
|
||||
13
VKernel/Kernel/drivers/fs/fat32/fat32_dir.py
Normal file
13
VKernel/Kernel/drivers/fs/fat32/fat32_dir.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import t, c
|
||||
|
||||
|
||||
sfn_checksum = types.sfn_checksum
|
||||
uni2oem_placeholder = types.uni2oem_placeholder
|
||||
lfn_get_char = types.lfn_get_char
|
||||
lfn_set_char = types.lfn_set_char
|
||||
lfn_extract = types.lfn_extract
|
||||
sfn_from_lfn = types.sfn_from_lfn
|
||||
sfn_to_str = types.sfn_to_str
|
||||
_split_path = types._split_path
|
||||
76
VKernel/Kernel/drivers/fs/fat32/fat32_diskio.py
Normal file
76
VKernel/Kernel/drivers/fs/fat32/fat32_diskio.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import drivers.storage.ide.ide as ide
|
||||
import fat32_types as types
|
||||
import spinlock
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_DRIVES: t.CDefine = 4
|
||||
|
||||
drive_initialized: t.CArray[t.CInt, MAX_DRIVES]
|
||||
drive_lock: spinlock._spinlock = spinlock._spinlock()
|
||||
|
||||
def status(pdrv: t.CUInt8T) -> types.DRESULT:
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def init(pdrv: t.CUInt8T) -> types.DRESULT:
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
drive_lock.lock()
|
||||
err: t.CInt = ide.init()
|
||||
if err != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_NOTRDY
|
||||
drive_initialized[pdrv] = 1
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def read(pdrv: t.CUInt8T, buff: t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: t.CUInt32T
|
||||
for i in range(count):
|
||||
rd_res: t.CInt = ide.readSector(sector + i, buff + (i * 512))
|
||||
if rd_res != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def write(pdrv: t.CUInt8T, buff: t.CConst | t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: t.CUInt32T
|
||||
for i in range(count):
|
||||
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def ioctl(pdrv: t.CUInt8T, cmd: t.CUInt8T, buff: t.CVoid | t.CPtr) -> types.DRESULT:
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
match cmd:
|
||||
case types.GET_SECTOR_COUNT:
|
||||
disk_size: t.CUInt64T = ide.getDiskSize()
|
||||
if disk_size == 0:
|
||||
c.Set(t.CUInt32T(buff, t.CPtr), 131072)
|
||||
elif disk_size > 0xFFFFFFFF:
|
||||
c.Set(t.CUInt32T(buff, t.CPtr), 0xFFFFFFFF)
|
||||
else:
|
||||
c.Set(t.CUInt32T(buff, t.CPtr), t.CUInt32T(disk_size))
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_SECTOR_SIZE:
|
||||
c.Set(t.CUInt16T(buff, t.CPtr), 512)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_BLOCK_SIZE:
|
||||
c.Set(t.CUInt32T(buff, t.CPtr), 1)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.CTRL_SYNC:
|
||||
return types.DRESULT.RES_OK
|
||||
case _:
|
||||
return types.DRESULT.RES_PARERR
|
||||
17
VKernel/Kernel/drivers/fs/fat32/fat32_file.py
Normal file
17
VKernel/Kernel/drivers/fs/fat32/fat32_file.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import t, c
|
||||
|
||||
|
||||
handle_table = types.handle_table
|
||||
lock_table = types.lock_table
|
||||
handles_initialized = types.handles_initialized
|
||||
handles_init = types.handles_init
|
||||
handle_alloc = types.handle_alloc
|
||||
lock_check = types.lock_check
|
||||
lock_acquire = types.lock_acquire
|
||||
lock_release = types.lock_release
|
||||
|
||||
def handle_free(fp):
|
||||
fp.is_open = 0
|
||||
fp.lock_count = 0
|
||||
143
VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.py
Normal file
143
VKernel/Kernel/drivers/fs/fat32/fat32_mkfs.py
Normal file
@@ -0,0 +1,143 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import fat32_time as ftime
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
def _div_round_up(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T:
|
||||
return (a + b - 1) / b
|
||||
|
||||
def _calc_fat_size(total_sectors: t.CUInt64T, reserved: t.CUInt32T, sec_per_clus: t.CUInt8T, num_fats: t.CUInt8T) -> t.CUInt32T:
|
||||
tmp: t.CUInt64T = total_sectors - t.CUInt64T(reserved)
|
||||
fat_sz: t.CUInt32T = 1
|
||||
while True:
|
||||
data_sectors: t.CUInt64T = tmp - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
|
||||
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
|
||||
needed: t.CUInt64T = _div_round_up(t.CUInt64T(total_clusters) * 4, 512)
|
||||
if needed <= t.CUInt64T(fat_sz): break
|
||||
fat_sz = t.CUInt32T(needed)
|
||||
return fat_sz
|
||||
|
||||
def _write_boot_sector(pdrv: t.CUInt8T, total_sectors: t.CUInt64T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T, fat_sz: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
|
||||
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
|
||||
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
|
||||
types._write16(c.Addr(buf[0]), 11, 512)
|
||||
buf[13] = sec_per_clus
|
||||
types._write16(c.Addr(buf[0]), 14, 32)
|
||||
buf[16] = 2
|
||||
types._write16(c.Addr(buf[0]), 17, 0)
|
||||
buf[21] = 0xF8
|
||||
types._write16(c.Addr(buf[0]), 22, 0)
|
||||
types._write16(c.Addr(buf[0]), 24, 63)
|
||||
types._write16(c.Addr(buf[0]), 26, 255)
|
||||
types._write32(c.Addr(buf[0]), 28, 0)
|
||||
types._write32(c.Addr(buf[0]), 32, t.CUInt32T(total_sectors))
|
||||
types._write32(c.Addr(buf[0]), 36, fat_sz)
|
||||
types._write16(c.Addr(buf[0]), 40, 0)
|
||||
types._write16(c.Addr(buf[0]), 42, 0)
|
||||
types._write32(c.Addr(buf[0]), 44, 2)
|
||||
types._write16(c.Addr(buf[0]), 48, 1)
|
||||
types._write16(c.Addr(buf[0]), 50, 6)
|
||||
buf[64] = 0x80
|
||||
buf[66] = 0x29
|
||||
types._write32(c.Addr(buf[0]), 67, vol_id)
|
||||
vol_label: t.CArray[t.CChar, 11]
|
||||
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
|
||||
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
|
||||
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
|
||||
i: t.CInt
|
||||
for i in range(11): buf[71 + i] = t.CUInt8T(vol_label[i])
|
||||
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
|
||||
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
|
||||
buf[510] = 0x55; buf[511] = 0xAA
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
|
||||
def _write_fsinfo(pdrv: t.CUInt8T, free_count: t.CUInt32T, next_free: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x41615252)
|
||||
types._write32(c.Addr(buf[0]), 484, 0x61417272)
|
||||
types._write32(c.Addr(buf[0]), 488, free_count)
|
||||
types._write32(c.Addr(buf[0]), 492, next_free)
|
||||
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
|
||||
|
||||
def _init_fat(pdrv: t.CUInt8T, fat_start: t.CUInt64T, fat_sz: t.CUInt32T, root_cluster: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
|
||||
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
|
||||
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
|
||||
if root_cluster >= 2:
|
||||
cluster_off: t.CUInt32T = root_cluster * 4
|
||||
sector_off: t.CUInt32T = cluster_off / 512
|
||||
byte_off: t.CUInt32T = cluster_off % 512
|
||||
if sector_off == 0:
|
||||
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: t.CUInt32T
|
||||
for s in range(1, fat_sz):
|
||||
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start) + s, 1)
|
||||
if res2 != types.DRESULT.RES_OK: return res2
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _init_root_dir(pdrv: t.CUInt8T, root_sector: t.CUInt64T, sec_per_clus: t.CUInt8T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: t.CUInt8T
|
||||
for s in range(sec_per_clus):
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(root_sector + t.CUInt64T(s)), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _calc_sec_per_clus(total_sectors: t.CUInt64T) -> t.CUInt8T:
|
||||
ts: t.CUInt64T = total_sectors
|
||||
if ts < 532480: return 1
|
||||
elif ts < 16777216: return 8
|
||||
elif ts < 33554432: return 16
|
||||
elif ts < 67108864: return 32
|
||||
else: return 64
|
||||
|
||||
def mkfs(pdrv: t.CUInt8T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T) -> types.FRESULT:
|
||||
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
|
||||
total_sectors_buf: t.CUInt32T = 0
|
||||
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
|
||||
total_sectors: t.CUInt64T = t.CUInt64T(total_sectors_buf)
|
||||
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
|
||||
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
|
||||
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
|
||||
return types.FRESULT.FR_INVALID_PARAMETER
|
||||
if vol_id == 0: vol_id = ftime.get_fattime()
|
||||
reserved: t.CUInt32T = 32
|
||||
num_fats: t.CUInt8T = 2
|
||||
fat_sz: t.CUInt32T = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
|
||||
data_sectors: t.CUInt64T = total_sectors - t.CUInt64T(reserved) - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
|
||||
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
|
||||
free_count: t.CUInt32T = total_clusters - 1
|
||||
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
|
||||
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
boot_backup: t.CArray[t.CUInt8T, 512]
|
||||
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
|
||||
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
|
||||
fsinfo_backup: t.CArray[t.CUInt8T, 512]
|
||||
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
|
||||
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
|
||||
fat_start: t.CUInt64T = t.CUInt64T(reserved)
|
||||
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
|
||||
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
fat2_start: t.CUInt64T = fat_start + t.CUInt64T(fat_sz)
|
||||
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
|
||||
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
root_sector: t.CUInt64T = fat2_start + t.CUInt64T(fat_sz)
|
||||
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
|
||||
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
return types.FRESULT.FR_OK
|
||||
147
VKernel/Kernel/drivers/fs/fat32/fat32_part.py
Normal file
147
VKernel/Kernel/drivers/fs/fat32/fat32_part.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_VOLUMES: t.CDefine = 4
|
||||
MAX_PARTITIONS: t.CDefine = 4
|
||||
|
||||
MBR_SIGNATURE: t.CDefine = 0xAA55
|
||||
PART_TYPE_FAT32: t.CDefine = 0x0C
|
||||
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
|
||||
PART_TYPE_FAT16: t.CDefine = 0x06
|
||||
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
|
||||
|
||||
class partition_entry:
|
||||
boot_flag: t.CUInt8T
|
||||
start_chs: t.CArray[t.CUInt8T, 3]
|
||||
part_type: t.CUInt8T
|
||||
end_chs: t.CArray[t.CUInt8T, 3]
|
||||
start_lba: t.CUInt32T
|
||||
total_sectors: t.CUInt32T
|
||||
|
||||
drive_pdrv: t.CArray[t.CUInt8T, MAX_VOLUMES]
|
||||
drive_num_parts: t.CArray[t.CInt, MAX_VOLUMES]
|
||||
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
|
||||
volume_mounted: t.CArray[t.CInt, MAX_VOLUMES]
|
||||
part_types: t.CArray[t.CUInt8T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_start_lbas: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_totals: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_is_fat32: t.CArray[t.CInt, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
|
||||
num_drives: t.CInt = 0
|
||||
|
||||
def _init():
|
||||
if num_drives > 0: return
|
||||
i: t.CInt
|
||||
for i in range(MAX_VOLUMES):
|
||||
drive_letter_map[i] = 0
|
||||
volume_mounted[i] = 0
|
||||
drive_pdrv[i] = 0
|
||||
drive_num_parts[i] = 0
|
||||
j: t.CInt
|
||||
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
|
||||
part_types[j] = 0
|
||||
part_start_lbas[j] = 0
|
||||
part_totals[j] = 0
|
||||
part_is_fat32[j] = 0
|
||||
|
||||
def _part_idx(drive: t.CInt, part: t.CInt) -> t.CInt:
|
||||
return drive * MAX_PARTITIONS + part
|
||||
|
||||
def parse_mbr(pdrv: t.CUInt8T, drive_idx: t.CInt) -> types.FRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
return types.FRESULT.FR_NO_FILESYSTEM
|
||||
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
|
||||
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
drive_pdrv[drive_idx] = pdrv
|
||||
drive_num_parts[drive_idx] = 0
|
||||
i: t.CInt
|
||||
for i in range(4):
|
||||
base: t.CUInt32T = 446 + t.CUInt32T(i * 16)
|
||||
ptype: t.CUInt8T = buf[base + 4]
|
||||
slba: t.CUInt32T = t.CUInt32T(buf[base + 8]) | (t.CUInt32T(buf[base + 9]) << 8) | (t.CUInt32T(buf[base + 10]) << 16) | (t.CUInt32T(buf[base + 11]) << 24)
|
||||
tsec: t.CUInt32T = t.CUInt32T(buf[base + 12]) | (t.CUInt32T(buf[base + 13]) << 8) | (t.CUInt32T(buf[base + 14]) << 16) | (t.CUInt32T(buf[base + 15]) << 24)
|
||||
if ptype != 0 and tsec > 0:
|
||||
pi: t.CInt = drive_num_parts[drive_idx]
|
||||
if pi < MAX_PARTITIONS:
|
||||
pidx: t.CInt = _part_idx(drive_idx, pi)
|
||||
part_types[pidx] = ptype
|
||||
part_start_lbas[pidx] = t.CUInt64T(slba)
|
||||
part_totals[pidx] = t.CUInt64T(tsec)
|
||||
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
|
||||
drive_num_parts[drive_idx] = pi + 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
_init()
|
||||
global num_drives
|
||||
num_drives = 0
|
||||
pdrv: t.CUInt8T
|
||||
for pdrv in range(MAX_VOLUMES):
|
||||
res: types.DRESULT = diskio.init(pdrv)
|
||||
if res != types.DRESULT.RES_OK: continue
|
||||
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
|
||||
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
else:
|
||||
drive_pdrv[num_drives] = pdrv
|
||||
drive_num_parts[num_drives] = 1
|
||||
pidx: t.CInt = _part_idx(num_drives, 0)
|
||||
part_types[pidx] = PART_TYPE_FAT32_LBA
|
||||
part_start_lbas[pidx] = 0
|
||||
part_totals[pidx] = 0
|
||||
part_is_fat32[pidx] = 1
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
num_drives = num_drives + 1
|
||||
if num_drives >= MAX_VOLUMES: break
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def get_drive(letter: t.CChar) -> t.CInt:
|
||||
_init()
|
||||
i: t.CInt
|
||||
for i in range(num_drives):
|
||||
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
|
||||
return i
|
||||
return -1
|
||||
|
||||
def get_pdrv(letter: t.CChar) -> t.CUInt8T:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_pdrv[idx]
|
||||
|
||||
def get_partition_start(letter: t.CChar, part_idx: t.CInt) -> t.CUInt64T:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: t.CInt = _part_idx(idx, part_idx)
|
||||
return part_start_lbas[pidx]
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> t.CInt:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_num_parts[idx]
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: t.CInt = _part_idx(idx, part_idx)
|
||||
return part_is_fat32[pidx]
|
||||
|
||||
def get_drive_count() -> t.CInt:
|
||||
return num_drives
|
||||
|
||||
def get_drive_letter(idx: t.CInt) -> t.CChar:
|
||||
if idx < 0 or idx >= num_drives: return 0
|
||||
return drive_letter_map[idx]
|
||||
|
||||
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
|
||||
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
|
||||
drive_letter_map[idx] = letter
|
||||
return types.FRESULT.FR_OK
|
||||
64
VKernel/Kernel/drivers/fs/fat32/fat32_time.py
Normal file
64
VKernel/Kernel/drivers/fs/fat32/fat32_time.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
rtc_cmos_addr: t.CUInt16T = 0x70
|
||||
rtc_cmos_data: t.CUInt16T = 0x71
|
||||
|
||||
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
|
||||
asm.outb(rtc_cmos_addr, reg)
|
||||
return asm.inb(rtc_cmos_data)
|
||||
|
||||
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def get_rtc_time() -> t.CUInt32T:
|
||||
while cmos_read(0x0A) & 0x80: pass
|
||||
sec: t.CUInt8T = cmos_read(0x00)
|
||||
min_: t.CUInt8T = cmos_read(0x02)
|
||||
hour: t.CUInt8T = cmos_read(0x04)
|
||||
day: t.CUInt8T = cmos_read(0x07)
|
||||
mon: t.CUInt8T = cmos_read(0x08)
|
||||
year: t.CUInt8T = cmos_read(0x09)
|
||||
reg_b: t.CUInt8T = cmos_read(0x0B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
fat_year: t.CUInt16T = t.CUInt16T(year) + 2000 - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(mon) << 5) | t.CUInt16T(day)
|
||||
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(min_) << 5) | (t.CUInt16T(sec) / 2)
|
||||
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
|
||||
|
||||
def get_fattime() -> t.CUInt32T:
|
||||
return get_rtc_time()
|
||||
|
||||
def to_year(ft: t.CUInt32T) -> t.CUInt16T:
|
||||
return t.CUInt16T((ft >> 25) & 0x7F) + 1980
|
||||
|
||||
def to_month(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 21) & 0x0F)
|
||||
|
||||
def to_day(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 16) & 0x1F)
|
||||
|
||||
def to_hour(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 11) & 0x1F)
|
||||
|
||||
def to_minute(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 5) & 0x3F)
|
||||
|
||||
def to_second(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft & 0x1F) * 2)
|
||||
|
||||
def make(year: t.CUInt16T, month: t.CUInt8T, day: t.CUInt8T, hour: t.CUInt8T, minute: t.CUInt8T, second: t.CUInt8T) -> t.CUInt32T:
|
||||
fat_year: t.CUInt16T = year - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(month) << 5) | t.CUInt16T(day)
|
||||
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(minute) << 5) | (t.CUInt16T(second) / 2)
|
||||
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
|
||||
1698
VKernel/Kernel/drivers/fs/fat32/fat32_types.py
Normal file
1698
VKernel/Kernel/drivers/fs/fat32/fat32_types.py
Normal file
File diff suppressed because it is too large
Load Diff
3
VKernel/Kernel/drivers/fs/fat32/fileio.py
Normal file
3
VKernel/Kernel/drivers/fs/fat32/fileio.py
Normal file
@@ -0,0 +1,3 @@
|
||||
import fat32
|
||||
|
||||
|
||||
146
VKernel/Kernel/drivers/input/keyboard/keyboard.py
Normal file
146
VKernel/Kernel/drivers/input/keyboard/keyboard.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperstring as string
|
||||
import t, c
|
||||
|
||||
|
||||
KBD_DATA: t.CDefine = 0x60
|
||||
KBD_STATUS: t.CDefine = 0x64
|
||||
KBD_COMMAND: t.CDefine = 0x64
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
KEY_RELEASED: t.CDefine = 0x80
|
||||
|
||||
buffer: t.CArray[t.CUInt8T, KBD_BUF_SIZE]
|
||||
buf_head: t.CStatic | t.CUInt32T = 0
|
||||
buf_tail: t.CStatic | t.CUInt32T = 0
|
||||
buf_count: t.CStatic | t.CUInt32T = 0
|
||||
|
||||
shift_l: t.CStatic | t.CUInt8T = 0
|
||||
shift_r: t.CStatic | t.CUInt8T = 0
|
||||
ctrl_l: t.CStatic | t.CUInt8T = 0
|
||||
alt_l: t.CStatic | t.CUInt8T = 0
|
||||
caps_lock: t.CStatic | t.CUInt8T = 0
|
||||
|
||||
scancode_set1: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
scancode_set1_shift: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
|
||||
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
def _wait_read():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def irq_handler() -> t.CInt:
|
||||
global buf_head, buf_tail, buf_count
|
||||
scancode: t.CUInt8T = asm.inb(KBD_DATA)
|
||||
if buf_count < KBD_BUF_SIZE:
|
||||
buffer[buf_tail] = scancode
|
||||
buf_tail = buf_tail + 1
|
||||
if buf_tail >= KBD_BUF_SIZE:
|
||||
buf_tail = 0
|
||||
buf_count += 1
|
||||
return 0
|
||||
|
||||
def read_scancode() -> t.CUInt8T:
|
||||
global buf_head, buf_count
|
||||
asm.cli()
|
||||
if buf_count == 0:
|
||||
asm.sti()
|
||||
return 0
|
||||
code: t.CUInt8T = buffer[buf_head]
|
||||
buf_head = buf_head + 1
|
||||
if buf_head >= KBD_BUF_SIZE:
|
||||
buf_head = 0
|
||||
buf_count -= 1
|
||||
asm.sti()
|
||||
return code
|
||||
|
||||
def scancode_to_ascii(scancode: t.CUInt8T) -> t.CChar:
|
||||
code: t.CUInt8T = scancode & ~t.CUInt8T(KEY_RELEASED)
|
||||
if code >= 128: return '\0'
|
||||
shifted: bool = (shift_l or shift_r) != 0
|
||||
if caps_lock and code >= 0x10 and code <= 0x32:
|
||||
shifted = not shifted
|
||||
if shifted:
|
||||
return scancode_set1_shift[code]
|
||||
return scancode_set1[code]
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
return buf_count
|
||||
|
||||
def init():
|
||||
drain: t.CUInt32T
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAD)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
ccb: t.CUInt8T = asm.inb(KBD_DATA)
|
||||
|
||||
ccb = ccb | 0x01
|
||||
ccb = ccb | 0x40
|
||||
ccb = ccb & 0xEF
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, ccb)
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAE)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, 0xF4)
|
||||
_wait_read()
|
||||
asm.inb(KBD_DATA)
|
||||
|
||||
idt.irqInstallHandler(1, irq_handler, "keyboard")
|
||||
134
VKernel/Kernel/drivers/input/mouse/mouse.py
Normal file
134
VKernel/Kernel/drivers/input/mouse/mouse.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.serial.uart.serial as serial
|
||||
import t, c
|
||||
|
||||
|
||||
MOUSE_DATA: t.CDefine = 0x60
|
||||
MOUSE_STATUS: t.CDefine = 0x64
|
||||
MOUSE_COMMAND: t.CDefine = 0x64
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
MOUSE_LEFT: t.CDefine = 0x01
|
||||
MOUSE_RIGHT: t.CDefine = 0x02
|
||||
MOUSE_MIDDLE: t.CDefine = 0x04
|
||||
|
||||
class mouse_packet:
|
||||
flags: t.CUInt8T
|
||||
dx: t.CInt8T
|
||||
dy: t.CInt8T
|
||||
buttons: t.CUInt8T
|
||||
|
||||
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
|
||||
pack_head: t.CStatic | t.CUInt32T = 0
|
||||
pack_tail: t.CStatic | t.CUInt32T = 0
|
||||
pack_count: t.CStatic | t.CUInt32T = 0
|
||||
|
||||
cycle: t.CStatic | t.CUInt8T = 0
|
||||
byte1: t.CStatic | t.CUInt8T = 0
|
||||
byte2: t.CStatic | t.CInt8T = 0
|
||||
byte3: t.CStatic | t.CInt8T = 0
|
||||
|
||||
mouse_x: t.CStatic | t.CInt32T = 0
|
||||
mouse_y: t.CStatic | t.CInt32T = 0
|
||||
mouse_buttons: t.CStatic | t.CUInt8T = 0
|
||||
|
||||
def _wait_read():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _write_cmd(cmd: t.CUInt8T):
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xD4)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, cmd)
|
||||
_wait_read()
|
||||
asm.inb(MOUSE_DATA)
|
||||
|
||||
def irq_handler() -> t.CInt:
|
||||
global cycle, byte1, byte2, byte3, pack_tail, pack_count
|
||||
status: t.CUInt8T = asm.inb(MOUSE_STATUS)
|
||||
if (status & 0x20) == 0: return 0
|
||||
data: t.CUInt8T = asm.inb(MOUSE_DATA)
|
||||
if cycle == 0:
|
||||
if (data & 0x08) != 0:
|
||||
byte1 = data
|
||||
cycle = 1
|
||||
return 0
|
||||
if cycle == 1:
|
||||
byte2 = data
|
||||
cycle = 2
|
||||
return 0
|
||||
byte3 = data
|
||||
cycle = 0
|
||||
if pack_count < MOUSE_BUF_SIZE:
|
||||
packets[pack_tail].flags = byte1
|
||||
packets[pack_tail].dx = byte2
|
||||
packets[pack_tail].dy = byte3
|
||||
packets[pack_tail].buttons = byte1 & t.CUInt8T(0x07)
|
||||
pack_tail = pack_tail + 1
|
||||
if pack_tail >= MOUSE_BUF_SIZE:
|
||||
pack_tail = 0
|
||||
pack_count += 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: mouse_packet | t.CPtr) -> t.CInt:
|
||||
global pack_head, pack_count
|
||||
asm.cli()
|
||||
if pack_count == 0:
|
||||
asm.sti()
|
||||
out.flags = 0
|
||||
out.dx = 0
|
||||
out.dy = 0
|
||||
out.buttons = 0
|
||||
return -1
|
||||
out.flags = packets[pack_head].flags
|
||||
out.dx = packets[pack_head].dx
|
||||
out.dy = packets[pack_head].dy
|
||||
out.buttons = packets[pack_head].buttons
|
||||
pack_head = pack_head + 1
|
||||
if pack_head >= MOUSE_BUF_SIZE:
|
||||
pack_head = 0
|
||||
pack_count -= 1
|
||||
asm.sti()
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
return pack_count
|
||||
|
||||
def get_x() -> t.CInt32T:
|
||||
return mouse_x
|
||||
|
||||
def get_y() -> t.CInt32T:
|
||||
return mouse_y
|
||||
|
||||
def get_buttons() -> t.CUInt8T:
|
||||
return mouse_buttons
|
||||
|
||||
def init():
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xA8)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
status: t.CUInt8T = asm.inb(MOUSE_DATA)
|
||||
status = status | 0x02
|
||||
status = status & 0xDF
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, status)
|
||||
_write_cmd(0xF6)
|
||||
_write_cmd(0xF4)
|
||||
pic.clearMask(12)
|
||||
idt.irqInstallHandler(12, irq_handler, "mouse")
|
||||
46
VKernel/Kernel/drivers/serial/uart/serial.py
Normal file
46
VKernel/Kernel/drivers/serial/uart/serial.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import platform.pch.pic as pic
|
||||
import su8250
|
||||
import t, c
|
||||
|
||||
|
||||
# 串口初始化
|
||||
def init():
|
||||
# 初始化COM1端口
|
||||
su8250.init(su8250.COM1_PORT)
|
||||
# 启用COM1中断(IRQ4)
|
||||
pic.clearMask(4)
|
||||
|
||||
# 发送一个字符到COM1
|
||||
def putc(cr: t.CChar):
|
||||
su8250.putchar(su8250.COM1_PORT, cr)
|
||||
|
||||
def putchar(cr: t.CChar):
|
||||
su8250.putchar(su8250.COM1_PORT, cr)
|
||||
|
||||
# 从COM1读取一个字符
|
||||
def getchar() -> t.CChar:
|
||||
return su8250.getchar(su8250.COM1_PORT)
|
||||
|
||||
# 发送一个字符串到COM1
|
||||
def puts(s: str):
|
||||
# 逐个字符发送,直接复用putchar的逻辑
|
||||
for i in s:
|
||||
putchar(i)
|
||||
|
||||
# 检查COM1是否有数据可读
|
||||
def isDataAvailable() -> t.CInt:
|
||||
return su8250.isDataAvailable(su8250.COM1_PORT)
|
||||
|
||||
# 检查COM1发送缓冲区是否为空
|
||||
def isTransmitEmpty() -> t.CInt:
|
||||
return su8250.isTransmitEmpty(su8250.COM1_PORT)
|
||||
|
||||
# 发送32位十六进制值到COM1
|
||||
def put_hex32(value: t.CUInt32T):
|
||||
hex_digits: t.CArray[t.CChar, None] = ["0123456789ABCDEF"]
|
||||
buffer: t.CArray[t.CChar, 9]
|
||||
for i in range(7, -1, -1):
|
||||
buffer[i] = hex_digits[value & 0xF]
|
||||
value >>= 4
|
||||
buffer[8] = '\0'
|
||||
puts(buffer)
|
||||
116
VKernel/Kernel/drivers/serial/uart/su8250.py
Normal file
116
VKernel/Kernel/drivers/serial/uart/su8250.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import platform.pch as pch
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
|
||||
|
||||
# 串口端口定义
|
||||
COM1_PORT: t.CDefine = 0x3F8 # COM1端口地址
|
||||
COM2_PORT: t.CDefine = 0x2F8 # COM2端口地址
|
||||
|
||||
# 8250/16550 UART寄存器偏移
|
||||
UART_RBR: t.CDefine = 0 # 接收缓冲区寄存器(读)
|
||||
UART_THR: t.CDefine = 0 # 发送保持寄存器(写)
|
||||
UART_DLL: t.CDefine = 0 # 除数锁存低位(写,DLAB=1)
|
||||
UART_IER: t.CDefine = 1 # 中断使能寄存器
|
||||
UART_DLM: t.CDefine = 1 # 除数锁存高位(写,DLAB=1)
|
||||
UART_FCR: t.CDefine = 2 # FIFO控制寄存器
|
||||
UART_IIR: t.CDefine = 2 # 中断识别寄存器(读)
|
||||
UART_LCR: t.CDefine = 3 # 线路控制寄存器
|
||||
UART_MCR: t.CDefine = 4 # 调制解调器控制寄存器
|
||||
UART_LSR: t.CDefine = 5 # 线路状态寄存器
|
||||
UART_MSR: t.CDefine = 6 # 调制解调器状态寄存器
|
||||
UART_SCR: t.CDefine = 7 # scratch register
|
||||
|
||||
|
||||
UART_LSR_THRE: t.CDefine = 0x20 # THRE:发送保持寄存器空
|
||||
UART_LSR_TEMT: t.CDefine = 0x40 # TEMT:发送移位寄存器空(真正的发送完成)
|
||||
|
||||
|
||||
# 线路控制寄存器位定义
|
||||
UART_LCR_DLAB: t.CDefine = 0x80 # 除数锁存访问位
|
||||
UART_LCR_8BIT: t.CDefine = 0x03 # 8位数据位
|
||||
|
||||
# 线路状态寄存器位定义
|
||||
UART_LSR_DR: t.CDefine = 0x01 # 数据就绪
|
||||
UART_LSR_THRE: t.CDefine = 0x20 # 发送保持寄存器空
|
||||
|
||||
# 波特率除数(115200 bps)
|
||||
BAUD_115200: t.CDefine = 1
|
||||
|
||||
|
||||
# 初始化UART 8250/16550
|
||||
def init(port: t.CUInt16T):
|
||||
# 1. 禁用中断
|
||||
asm.outb(port + UART_IER, 0x00)
|
||||
delay(1000)
|
||||
# 2. 设置波特率除数(115200 bps)
|
||||
asm.outb(port + UART_LCR, UART_LCR_DLAB) # 设置DLAB位
|
||||
delay(1000)
|
||||
asm.outb(port + UART_DLL, 0x01) # 除数低位 (115200 bps)
|
||||
delay(1000)
|
||||
asm.outb(port + UART_DLM, 0x00) # 除数高位
|
||||
delay(1000)
|
||||
# 3. 设置线路控制:8位数据位,1位停止位,无校验
|
||||
asm.outb(port + UART_LCR, UART_LCR_8BIT)
|
||||
delay(1000)
|
||||
# 4. 初始化FIFO
|
||||
asm.outb(port + UART_FCR, 0x07) # 启用FIFO,清除接收和发送FIFO
|
||||
delay(1000)
|
||||
# 5. 设置调制解调器控制
|
||||
asm.outb(port + UART_MCR, 0x03) # 启用DTR、RTS
|
||||
delay(1000)
|
||||
# 6. 清除任何待处理的中断
|
||||
asm.inb(port + UART_IIR)
|
||||
delay(1000)
|
||||
asm.inb(port + UART_RBR)
|
||||
delay(1000)
|
||||
# 7. 等待一段时间让设备稳定
|
||||
delay(10000)
|
||||
|
||||
# 延迟函数
|
||||
def delay(count: t.CInt):
|
||||
for i in range(count): c.Asm("nop")
|
||||
|
||||
# 检查发送缓冲区是否为空
|
||||
def isTransmitEmpty(port: t.CUInt16T) -> t.CInt:
|
||||
return asm.inb(port + UART_LSR) & UART_LSR_THRE
|
||||
|
||||
def putchar(port: t.CUInt16T, cr: t.CChar):
|
||||
# 1. 处理换行符:串口终端需要\r\n才会正确换行,只发\n会错位
|
||||
if cr == '\n':
|
||||
# 直接发送\r,避免递归调用
|
||||
timeout: t.CUInt32T = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
if timeout == 0: return
|
||||
asm.outb(port + UART_THR, '\r')
|
||||
timeout = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_TEMT) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
# 2. 等待发送缓冲区为空
|
||||
timeout: t.CUInt32T = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
if timeout == 0: return
|
||||
# 3. 发送字符
|
||||
asm.outb(port + UART_THR, cr)
|
||||
# 4. 等待发送完成
|
||||
timeout = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_TEMT) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
|
||||
# 检查是否有数据可读
|
||||
def isDataAvailable(port: t.CUInt16T) -> t.CInt:
|
||||
return asm.inb(port + UART_LSR) & UART_LSR_DR
|
||||
|
||||
# 读取一个字符
|
||||
def getchar(port: t.CUInt16T) -> t.CChar:
|
||||
# 等待数据可用
|
||||
while not isDataAvailable(port): pass
|
||||
# 读取字符
|
||||
return asm.inb(port + UART_RBR)
|
||||
161
VKernel/Kernel/drivers/storage/ide/ide.py
Normal file
161
VKernel/Kernel/drivers/storage/ide/ide.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import asm
|
||||
import t, c
|
||||
import serial
|
||||
import viperlib
|
||||
import pci
|
||||
|
||||
|
||||
class IDError(t.CEnum):
|
||||
IDE_ERR_NONE: t.State = 0
|
||||
IDE_ERR_TIMEOUT: t.State
|
||||
IDE_ERR_DEVICE_ERROR: t.State
|
||||
IDE_ERR_DEVICE_BUSY: t.State
|
||||
IDE_ERR_INVALID_PARAM: t.State
|
||||
IDE_ERR_BUFFER_NULL: t.State
|
||||
IDE_ERR_SECTOR_COUNT: t.State
|
||||
IDE_ERR_DEVICE_NOT_READY: t.State
|
||||
IDE_ERR_DEVICE_FAILURE: t.State
|
||||
IDE_ERR_COMMAND_FAILED: t.State
|
||||
IDE_ERR_INVALID_LBA: t.State
|
||||
|
||||
IDE_baseport_PRIMARY: t.CDefine = 0x1F0
|
||||
IDE_baseport_SECONDARY: t.CDefine = 0x170
|
||||
|
||||
IDE_STATUS_BSY: t.CDefine = 0x80
|
||||
IDE_STATUS_DRDY: t.CDefine = 0x40
|
||||
IDE_STATUS_DF: t.CDefine = 0x20
|
||||
IDE_STATUS_DRQ: t.CDefine = 0x08
|
||||
IDE_STATUS_ERR: t.CDefine = 0x01
|
||||
|
||||
SECTOR_SIZE: t.CDefine = 512
|
||||
|
||||
_ide_initialized: t.CInt = 0
|
||||
|
||||
def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout: t.CInt = 100000
|
||||
while timeout > 0:
|
||||
status: t.CUInt8T = asm.inb(baseport + 7)
|
||||
if status & IDE_STATUS_DF:
|
||||
return IDError.IDE_ERR_DEVICE_FAILURE
|
||||
if not status & IDE_STATUS_BSY and status & IDE_STATUS_DRDY:
|
||||
return IDError.IDE_ERR_NONE
|
||||
timeout -= 1
|
||||
return IDError.IDE_ERR_TIMEOUT
|
||||
|
||||
def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout: t.CInt = 100000
|
||||
while timeout > 0:
|
||||
status: t.CUInt8T = asm.inb(baseport + 7)
|
||||
if status & IDE_STATUS_ERR: return IDError.IDE_ERR_DEVICE_ERROR
|
||||
if status & IDE_STATUS_DF: return IDError.IDE_ERR_DEVICE_FAILURE
|
||||
if not status & IDE_STATUS_BSY and (status & IDE_STATUS_DRQ or status & IDE_STATUS_DRDY):
|
||||
return IDError.IDE_ERR_NONE
|
||||
timeout -= 1
|
||||
return IDError.IDE_ERR_TIMEOUT
|
||||
|
||||
def init() -> t.CInt:
|
||||
if _ide_initialized: return IDError.IDE_ERR_NONE
|
||||
dbg: t.CArray[t.CChar, 120]
|
||||
bus: t.CUInt8T
|
||||
dev_n: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
for bus in range(2):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: t.CUInt32T = pci.pci_get_class(bus, dev_n, func)
|
||||
if cls == 0x010180 or cls == 0x0101:
|
||||
cmd: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x04)
|
||||
pci.pci_write32(bus, dev_n, func, 0x04, t.CUInt32T(cmd | 0x0007))
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", t.CInt(bus), t.CInt(dev_n), t.CInt(func), t.CUInt32T(pci.pci_read16(bus, dev_n, func, 0x04)))
|
||||
serial.puts(dbg)
|
||||
asm.outb(0x3F6, 0x04)
|
||||
i: t.CInt
|
||||
for i in range(10000):
|
||||
asm.nop()
|
||||
asm.outb(0x3F6, 0x00)
|
||||
for i in range(10000):
|
||||
asm.nop()
|
||||
status: t.CUInt8T = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", t.CUInt32T(status))
|
||||
serial.puts(dbg)
|
||||
_ide_initialized = 1
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def readSector(lba: t.CUInt32T, buffer: t.CVoid | t.CPtr) -> t.CInt:
|
||||
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
||||
dbg: t.CArray[t.CChar, 120]
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE:
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", t.CInt(err))
|
||||
serial.puts(dbg)
|
||||
return err
|
||||
asm.outb(0x3F6, 0x02)
|
||||
asm.outb(0x1F2, 1)
|
||||
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
|
||||
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F7, 0x20)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE:
|
||||
st: t.CUInt8T = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", t.CInt(err), t.CUInt32T(st))
|
||||
serial.puts(dbg)
|
||||
return err
|
||||
st2: t.CUInt8T = asm.inb(0x1F7)
|
||||
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
|
||||
for j in range(256):
|
||||
c.Set(c.Deref(buf), asm.inw(0x1F0))
|
||||
buf += 1
|
||||
first_byte: t.CUInt8T = c.Deref(t.CUInt8T(buffer, t.CPtr))
|
||||
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, t.CUInt32T(st2), t.CUInt32T(first_byte))
|
||||
# serial.puts(dbg)
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def writeSector(lba: t.CUInt32T, buffer: t.CConst | t.CVoid | t.CPtr) -> t.CInt:
|
||||
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return err
|
||||
asm.outb(0x3F6, 0x02)
|
||||
asm.outb(0x1F2, 1)
|
||||
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
|
||||
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F7, 0x30)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return err
|
||||
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
|
||||
for j in range(256):
|
||||
val: t.CUInt16T = c.Deref(buf)
|
||||
asm.outw(0x1F0, val)
|
||||
buf += 1
|
||||
asm.outb(0x1F7, 0xE7)
|
||||
waitReady(IDE_baseport_PRIMARY)
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def getDiskSize() -> t.CUInt64T:
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return 0
|
||||
asm.outb(0x1F6, 0xE0)
|
||||
asm.outb(0x1F7, 0xEC)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return 0
|
||||
status: t.CUInt8T = asm.inb(0x1F7)
|
||||
if not status & IDE_STATUS_DRDY: return 0
|
||||
if status & IDE_STATUS_ERR: return 0
|
||||
identify_data: t.CArray[t.CUInt16T, 256]
|
||||
for i in range(256):
|
||||
identify_data[i] = asm.inw(0x1F0)
|
||||
totalSectors: t.CUInt64T = identify_data[60] | t.CUInt64T(identify_data[61]) << 16
|
||||
if identify_data[83] & (1 << 10):
|
||||
lba48_sectors: t.CUInt64T = (
|
||||
t.CUInt64T(identify_data[100]) |
|
||||
t.CUInt64T(identify_data[101]) << 16 |
|
||||
t.CUInt64T(identify_data[102]) << 32 |
|
||||
t.CUInt64T(identify_data[103]) << 48)
|
||||
if lba48_sectors > totalSectors:
|
||||
totalSectors = lba48_sectors
|
||||
return totalSectors
|
||||
37
VKernel/Kernel/drivers/usb/hid/hid.py
Normal file
37
VKernel/Kernel/drivers/usb/hid/hid.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
|
||||
HID_BOOT_PROTOCOL: t.CDefine = 0
|
||||
HID_REPORT_PROTOCOL: t.CDefine = 1
|
||||
|
||||
HID_KBD_REPORT_SIZE: t.CDefine = 8
|
||||
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
|
||||
|
||||
class hid_kbd_report(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
reserved: t.CUInt8T
|
||||
keycode: t.CArray[t.CUInt8T, 6]
|
||||
|
||||
class hid_mouse_report(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt8T
|
||||
dy: t.CInt8T
|
||||
wheel: t.CInt8T
|
||||
|
||||
def init_keyboard(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x01: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def init_mouse(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x02: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
|
||||
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
111
VKernel/Kernel/drivers/usb/hid/usb_kbd.py
Normal file
111
VKernel/Kernel/drivers/usb/hid/usb_kbd.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
KBD_EVT_PRESS: t.CDefine = 0
|
||||
KBD_EVT_RELEASE: t.CDefine = 1
|
||||
|
||||
class usb_kbd_event(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
keycode: t.CUInt8T
|
||||
event_type: t.CUInt8T
|
||||
|
||||
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
|
||||
kbd_buf_head: t.CInt = 0
|
||||
kbd_buf_tail: t.CInt = 0
|
||||
kbd_buf_count: t.CInt = 0
|
||||
kbd_dev: usb.usb_device | t.CPtr = None
|
||||
kbd_report: hid.hid_kbd_report
|
||||
kbd_prev_keycodes: t.CArray[t.CUInt8T, 6]
|
||||
kbd_initialized: t.CInt = 0
|
||||
kbd_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global kbd_dev, kbd_initialized, kbd_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
|
||||
if dev is None:
|
||||
serial.puts("[usb_kbd] no USB keyboard found\n")
|
||||
return -1
|
||||
kbd_dev = dev
|
||||
if hid.init_keyboard(dev) != 0:
|
||||
serial.puts("[usb_kbd] init failed\n")
|
||||
return -2
|
||||
kbd_initialized = 1
|
||||
serial.puts("[usb_kbd] initialized\n")
|
||||
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if kbd_slot_id < 0:
|
||||
serial.puts("[usb_kbd] register callback failed\n")
|
||||
kbd_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
|
||||
if kbd_initialized == 0: return 0
|
||||
i: t.CInt
|
||||
j: t.CInt
|
||||
for i in range(6):
|
||||
code: t.CUInt8T = kbd_report.keycode[i]
|
||||
if code == 0: continue
|
||||
found: t.CInt = 0
|
||||
for j in range(6):
|
||||
if code == kbd_prev_keycodes[j]:
|
||||
found = 1
|
||||
break
|
||||
if found == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = code
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
prev: t.CUInt8T = kbd_prev_keycodes[i]
|
||||
if prev == 0: continue
|
||||
found2: t.CInt = 0
|
||||
for j in range(6):
|
||||
if prev == kbd_report.keycode[j]:
|
||||
found2 = 1
|
||||
break
|
||||
if found2 == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = prev
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
kbd_prev_keycodes[i] = kbd_report.keycode[i]
|
||||
dev: usb.usb_device | t.CPtr = kbd_dev
|
||||
if dev is not None and kbd_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def poll() -> t.CInt:
|
||||
if kbd_initialized == 0: return 0
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_event(out: usb_kbd_event | t.CPtr) -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_count
|
||||
if kbd_buf_count == 0: return -1
|
||||
out.modifier = kbd_buf[kbd_buf_head].modifier
|
||||
out.keycode = kbd_buf[kbd_buf_head].keycode
|
||||
out.event_type = kbd_buf[kbd_buf_head].event_type
|
||||
kbd_buf_head = kbd_buf_head + 1
|
||||
if kbd_buf_head >= KBD_BUF_SIZE:
|
||||
kbd_buf_head = 0
|
||||
kbd_buf_count -= 1
|
||||
return 0
|
||||
77
VKernel/Kernel/drivers/usb/hid/usb_mouse.py
Normal file
77
VKernel/Kernel/drivers/usb/hid/usb_mouse.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
class usb_mouse_packet(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt16T
|
||||
dy: t.CInt16T
|
||||
wheel: t.CInt8T
|
||||
|
||||
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
|
||||
mse_buf_head: t.CInt = 0
|
||||
mse_buf_tail: t.CInt = 0
|
||||
mse_buf_count: t.CInt = 0
|
||||
mse_dev: usb.usb_device | t.CPtr = None
|
||||
mse_report: hid.hid_mouse_report
|
||||
mse_initialized: t.CInt = 0
|
||||
mse_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global mse_dev, mse_initialized, mse_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
|
||||
if dev is None:
|
||||
serial.puts("[usb_mse] no USB mouse found\n")
|
||||
return -1
|
||||
mse_dev = dev
|
||||
if hid.init_mouse(dev) != 0:
|
||||
serial.puts("[usb_mse] init failed\n")
|
||||
return -2
|
||||
mse_initialized = 1
|
||||
serial.puts("[usb_mse] initialized\n")
|
||||
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if mse_slot_id < 0:
|
||||
serial.puts("[usb_mse] register callback failed\n")
|
||||
mse_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
global mse_buf_head, mse_buf_tail, mse_buf_count
|
||||
if mse_initialized == 0: return 0
|
||||
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
|
||||
if mse_buf_count < MOUSE_BUF_SIZE:
|
||||
mse_buf[mse_buf_tail].buttons = mse_report.buttons
|
||||
mse_buf[mse_buf_tail].dx = t.CInt16T(mse_report.dx)
|
||||
mse_buf[mse_buf_tail].dy = t.CInt16T(mse_report.dy)
|
||||
mse_buf[mse_buf_tail].wheel = mse_report.wheel
|
||||
mse_buf_tail = mse_buf_tail + 1
|
||||
if mse_buf_tail >= MOUSE_BUF_SIZE:
|
||||
mse_buf_tail = 0
|
||||
mse_buf_count += 1
|
||||
dev: usb.usb_device | t.CPtr = mse_dev
|
||||
if dev is not None and mse_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if mse_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: usb_mouse_packet | t.CPtr) -> t.CInt:
|
||||
global mse_buf_head, mse_buf_count
|
||||
if mse_buf_count == 0: return -1
|
||||
out.buttons = mse_buf[mse_buf_head].buttons
|
||||
out.dx = mse_buf[mse_buf_head].dx
|
||||
out.dy = mse_buf[mse_buf_head].dy
|
||||
out.wheel = mse_buf[mse_buf_head].wheel
|
||||
mse_buf_head = mse_buf_head + 1
|
||||
if mse_buf_head >= MOUSE_BUF_SIZE:
|
||||
mse_buf_head = 0
|
||||
mse_buf_count -= 1
|
||||
return 0
|
||||
93
VKernel/Kernel/drivers/usb/pci.py
Normal file
93
VKernel/Kernel/drivers/usb/pci.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
|
||||
PCI_CONFIG_DATA: t.CDefine = 0xCFC
|
||||
|
||||
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
|
||||
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
|
||||
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
|
||||
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
|
||||
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
|
||||
|
||||
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
|
||||
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
|
||||
|
||||
class pci_device(t.CStruct):
|
||||
bus: t.CUInt8T
|
||||
dev: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
vendor_id: t.CUInt16T
|
||||
device_id: t.CUInt16T
|
||||
class_code: t.CUInt32T
|
||||
irq: t.CUInt8T
|
||||
bar: t.CArray[t.CUInt32T, 6]
|
||||
|
||||
def pci_read32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt32T:
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
return asm.inl(PCI_CONFIG_DATA)
|
||||
|
||||
def pci_write32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T, value: t.CUInt32T):
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
asm.outl(PCI_CONFIG_DATA, value)
|
||||
|
||||
def pci_read16(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt16T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x02) * 8
|
||||
return t.CUInt16T((val >> shift) & 0xFFFF)
|
||||
|
||||
def pci_read8(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt8T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x03) * 8
|
||||
return t.CUInt8T((val >> shift) & 0xFF)
|
||||
|
||||
def pci_get_class(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T) -> t.CUInt32T:
|
||||
cls: t.CUInt8T = pci_read8(bus, dev, func, 0x0B)
|
||||
sub: t.CUInt8T = pci_read8(bus, dev, func, 0x0A)
|
||||
proto: t.CUInt8T = pci_read8(bus, dev, func, 0x09)
|
||||
return (t.CUInt32T(cls) << 16) | (t.CUInt32T(sub) << 8) | t.CUInt32T(proto)
|
||||
|
||||
def pci_get_bar(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, bar_idx: t.CUInt8T) -> t.CUInt32T:
|
||||
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
|
||||
|
||||
def pci_enable_device(dev: pci_device | t.CPtr):
|
||||
cmd: t.CUInt16T = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
|
||||
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
|
||||
pci_write32(dev.bus, dev.dev, dev.func, 0x04, t.CUInt32T(cmd))
|
||||
|
||||
def pci_fill_device(bus: t.CUInt8T, dev_n: t.CUInt8T, func: t.CUInt8T, out: pci_device | t.CPtr):
|
||||
out.bus = bus
|
||||
out.dev = dev_n
|
||||
out.func = func
|
||||
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
|
||||
out.device_id = pci_read16(bus, dev_n, func, 0x02)
|
||||
out.class_code = pci_get_class(bus, dev_n, func)
|
||||
out.irq = pci_read8(bus, dev_n, func, 0x3C)
|
||||
i: t.CInt
|
||||
for i in range(6):
|
||||
out.bar[i] = pci_get_bar(bus, dev_n, func, t.CUInt8T(i))
|
||||
|
||||
_uhci_dev: pci_device
|
||||
_uhci_found: t.CInt = 0
|
||||
|
||||
def find_uhci() -> t.CUInt16T:
|
||||
global _uhci_dev, _uhci_found
|
||||
bus: t.CUInt8T
|
||||
dev_n: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
for bus in range(1):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: t.CUInt16T = pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: t.CUInt32T = pci_get_class(bus, dev_n, func)
|
||||
if cls == PCI_CLASS_SERIAL_UHCI:
|
||||
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
|
||||
pci_enable_device(c.Addr(_uhci_dev))
|
||||
_uhci_found = 1
|
||||
bar: t.CUInt32T = _uhci_dev.bar[4]
|
||||
io_base: t.CUInt16T = t.CUInt16T(bar & 0xFFFE)
|
||||
return io_base
|
||||
return 0
|
||||
415
VKernel/Kernel/drivers/usb/uhci.py
Normal file
415
VKernel/Kernel/drivers/usb/uhci.py
Normal file
@@ -0,0 +1,415 @@
|
||||
import t, c
|
||||
import asm
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import platform.pch.timer as timer
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.usb.pci as pci
|
||||
|
||||
UHCI_USBCMD: t.CDefine = 0x00
|
||||
UHCI_USBSTS: t.CDefine = 0x02
|
||||
UHCI_USBINTR: t.CDefine = 0x04
|
||||
UHCI_FRNUM: t.CDefine = 0x06
|
||||
UHCI_FLBASEADD: t.CDefine = 0x08
|
||||
UHCI_SOFMOD: t.CDefine = 0x0C
|
||||
UHCI_PORTSC1: t.CDefine = 0x10
|
||||
UHCI_PORTSC2: t.CDefine = 0x12
|
||||
|
||||
UHCI_CMD_RUN: t.CDefine = 0x0001
|
||||
UHCI_CMD_HCRESET: t.CDefine = 0x0002
|
||||
UHCI_CMD_GRESET: t.CDefine = 0x0004
|
||||
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
|
||||
UHCI_CMD_CF: t.CDefine = 0x0040
|
||||
|
||||
UHCI_STS_HCHALTED: t.CDefine = 0x0020
|
||||
UHCI_STS_USBINT: t.CDefine = 0x0001
|
||||
UHCI_STS_USBERRINT: t.CDefine = 0x0002
|
||||
UHCI_STS_RESUME: t.CDefine = 0x0004
|
||||
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
|
||||
UHCI_INTR_RESUME: t.CDefine = 0x0002
|
||||
UHCI_INTR_IOC: t.CDefine = 0x0004
|
||||
UHCI_INTR_SHORT: t.CDefine = 0x0008
|
||||
|
||||
UHCI_PORT_CONNECT: t.CDefine = 0x0001
|
||||
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
|
||||
UHCI_PORT_ENABLE: t.CDefine = 0x0004
|
||||
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
|
||||
UHCI_PORT_RESET: t.CDefine = 0x0200
|
||||
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
|
||||
|
||||
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
|
||||
TD_CTRL_IOC: t.CDefine = 0x01000000
|
||||
TD_CTRL_LS: t.CDefine = 0x04000000
|
||||
TD_CTRL_SPD: t.CDefine = 0x20000000
|
||||
TD_CTRL_CERR_SHIFT: t.CDefine = 27
|
||||
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
|
||||
|
||||
TD_TOKEN_SETUP: t.CDefine = 0x2D
|
||||
TD_TOKEN_IN: t.CDefine = 0x69
|
||||
TD_TOKEN_OUT: t.CDefine = 0xE1
|
||||
|
||||
TD_TOKEN_DATA0: t.CDefine = 0
|
||||
TD_TOKEN_DATA1: t.CDefine = 1
|
||||
|
||||
TD_LINK_TERMINATE: t.CDefine = 0x00000001
|
||||
TD_LINK_QH: t.CDefine = 0x00000002
|
||||
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
|
||||
|
||||
UHCI_NUM_FRAMES: t.CDefine = 1024
|
||||
UHCI_INT_SLOTS: t.CDefine = 4
|
||||
|
||||
class uhci_td(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
ctrl_status: t.CUInt32T
|
||||
token: t.CUInt32T
|
||||
buffer: t.CUInt32T
|
||||
|
||||
class uhci_qh(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
element: t.CUInt32T
|
||||
|
||||
class int_slot(t.CStruct):
|
||||
td: uhci_td | t.CPtr
|
||||
callback: t.CInt | t.CPtr
|
||||
active: t.CInt
|
||||
qh: uhci_qh | t.CPtr
|
||||
|
||||
_io_base: t.CUInt16T = 0
|
||||
_frame_list: t.CUInt32T | t.CPtr = None
|
||||
_ctrl_qh: uhci_qh | t.CPtr = None
|
||||
_bulk_qh: uhci_qh | t.CPtr = None
|
||||
_irq: t.CInt = -1
|
||||
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
|
||||
_int_slot_count: t.CInt = 0
|
||||
|
||||
def _reg_read16(offset: t.CUInt16T) -> t.CUInt16T:
|
||||
return asm.inw(_io_base + offset)
|
||||
|
||||
def _reg_write16(offset: t.CUInt16T, value: t.CUInt16T):
|
||||
asm.outw(_io_base + offset, value)
|
||||
|
||||
def _reg_read32(offset: t.CUInt16T) -> t.CUInt32T:
|
||||
return asm.inl(_io_base + offset)
|
||||
|
||||
def _reg_write32(offset: t.CUInt16T, value: t.CUInt32T):
|
||||
asm.outl(_io_base + offset, value)
|
||||
|
||||
def _uhci_irq_handler() -> t.CInt:
|
||||
sts: t.CUInt16T = _reg_read16(UHCI_USBSTS)
|
||||
_reg_write16(UHCI_USBSTS, sts)
|
||||
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
|
||||
return 0
|
||||
for si in range(_int_slot_count):
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
if slot.active and slot.td is not None and slot.callback is not None:
|
||||
status: t.CUInt32T = slot.td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
slot.active = 0
|
||||
c.Asm(f"""mov rbp, rsp
|
||||
and rsp, -16
|
||||
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsp, rbp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RBX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
|
||||
t.ASM_DESCR.CLOBBER_RBP])
|
||||
return 0
|
||||
|
||||
def register_int_callback(cb: t.CInt | t.CPtr) -> t.CInt:
|
||||
global _int_slot_count
|
||||
if _int_slot_count >= UHCI_INT_SLOTS:
|
||||
return -1
|
||||
si: t.CInt = _int_slot_count
|
||||
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if qh is None:
|
||||
return -2
|
||||
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(qh, 0, 0, 1)
|
||||
_qh_set_element(qh, 0, 1)
|
||||
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
|
||||
if td is None:
|
||||
return -3
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
slot.td = td
|
||||
slot.callback = cb
|
||||
slot.active = 0
|
||||
slot.qh = qh
|
||||
_int_slot_count = si + 1
|
||||
_rebuild_int_chain()
|
||||
return si
|
||||
|
||||
def schedule_int_transfer(slot_id: t.CInt, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, toggle_ptr: t.CUInt8T | t.CPtr, buf: t.CVoid | t.CPtr):
|
||||
if slot_id < 0 or slot_id >= _int_slot_count:
|
||||
return
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
|
||||
td: uhci_td | t.CPtr = slot.td
|
||||
qh: uhci_qh | t.CPtr = slot.qh
|
||||
if td is None or qh is None:
|
||||
return
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
_td_set_link(td, 0, 0, 1)
|
||||
_td_set_ctrl(td, ls, max_pkt)
|
||||
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
|
||||
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
|
||||
td.buffer = t.CUInt32T(t.CUInt64T(buf))
|
||||
_qh_set_element(qh, t.CUInt32T(t.CUInt64T(td)), 0)
|
||||
slot.active = 1
|
||||
|
||||
def _rebuild_int_chain():
|
||||
if _int_slot_count == 0:
|
||||
return
|
||||
first_qh: uhci_qh | t.CPtr = None
|
||||
prev_qh: uhci_qh | t.CPtr = None
|
||||
for si in range(_int_slot_count):
|
||||
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
|
||||
if cur_qh is not None:
|
||||
if first_qh is None:
|
||||
first_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(cur_qh)) | TD_LINK_QH, 1, 0)
|
||||
prev_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(_ctrl_qh)) | TD_LINK_QH, 1, 0)
|
||||
if first_qh is not None:
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(t.CUInt64T(first_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
def _td_set_link(td: uhci_td | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
td.link = val
|
||||
|
||||
def _td_set_token(td: uhci_td | t.CPtr, pid: t.CUInt8T, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, toggle: t.CUInt8T, max_len: t.CUInt16T):
|
||||
len_bits: t.CUInt32T
|
||||
if max_len == 0:
|
||||
len_bits = 0x7FF
|
||||
else:
|
||||
len_bits = t.CUInt32T(max_len) - 1
|
||||
td.token = (t.CUInt32T(pid) << 0) | (t.CUInt32T(dev_addr) << 8) | (t.CUInt32T(endpoint & 0x0F) << 15) | (t.CUInt32T(toggle & 1) << 19) | (len_bits << 21)
|
||||
|
||||
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: t.CInt, maxlen: t.CUInt16T):
|
||||
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
|
||||
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
|
||||
|
||||
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.link = val
|
||||
|
||||
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.element = val
|
||||
|
||||
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: t.CInt) -> t.CInt:
|
||||
start: t.CUInt64T = timer.timer_get_ticks()
|
||||
deadline: t.CUInt64T = start + t.CUInt64T(timeout_ms)
|
||||
poll_cnt: t.CInt = 0
|
||||
while timer.timer_get_ticks() < deadline:
|
||||
status: t.CUInt32T = td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
if (status & 0x00600000) != 0:
|
||||
return -1
|
||||
return 0
|
||||
poll_cnt += 1
|
||||
if poll_cnt >= 100:
|
||||
poll_cnt = 0
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
return -2
|
||||
|
||||
def reset(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _io_base
|
||||
_io_base = io_base
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
|
||||
i: t.CInt
|
||||
for i in range(1000):
|
||||
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
|
||||
break
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, 0x0000)
|
||||
return 0
|
||||
|
||||
def init(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
|
||||
_io_base = io_base
|
||||
_int_slot_count = 0
|
||||
|
||||
serial.puts("[uhci] resetting...\n")
|
||||
if reset(io_base) != 0:
|
||||
serial.puts("[uhci] reset failed\n")
|
||||
return -1
|
||||
|
||||
serial.puts("[uhci] allocating frame list...\n")
|
||||
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
|
||||
if _frame_list is None:
|
||||
serial.puts("[uhci] frame list alloc failed\n")
|
||||
return -2
|
||||
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
|
||||
|
||||
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _ctrl_qh is None:
|
||||
serial.puts("[uhci] ctrl_qh alloc failed\n")
|
||||
return -3
|
||||
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_ctrl_qh, 0, 0, 1)
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
|
||||
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _bulk_qh is None:
|
||||
serial.puts("[uhci] bulk_qh alloc failed\n")
|
||||
return -4
|
||||
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_bulk_qh, 0, 0, 1)
|
||||
_qh_set_element(_bulk_qh, 0, 1)
|
||||
|
||||
serial.puts("[uhci] setting up frame list...\n")
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(c.Addr(_ctrl_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
_reg_write32(UHCI_FLBASEADD, t.CUInt32T(t.CUInt64T(_frame_list)))
|
||||
_reg_write16(UHCI_FRNUM, 0)
|
||||
_reg_write16(UHCI_SOFMOD, 64)
|
||||
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
|
||||
|
||||
_irq = t.CInt(pci._uhci_dev.irq)
|
||||
if _irq > 0 and _irq < 16:
|
||||
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
|
||||
pic.clearMask(t.CUInt8T(_irq))
|
||||
|
||||
serial.puts("[uhci] started\n")
|
||||
return 0
|
||||
|
||||
def port_reset(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_CONNECT) == 0:
|
||||
return -1
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, 0x0000)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, 0x0000)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_ENABLE) == 0:
|
||||
return -2
|
||||
|
||||
return 0
|
||||
|
||||
def port_is_connected(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_CONNECT: return 1
|
||||
return 0
|
||||
|
||||
def port_is_low_speed(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_LOW_SPEED: return 1
|
||||
return 0
|
||||
|
||||
def control_transfer(dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup_buf: t.CVoid | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
|
||||
td_count: t.CInt = 2
|
||||
if data_len > 0:
|
||||
td_count = td_count + 1
|
||||
total: t.CUInt64T = t.CUInt64T(td_count) * uhci_td.__sizeof__()
|
||||
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
|
||||
if tds is None: return -1
|
||||
string.memset(c.Addr(tds), 0, total)
|
||||
|
||||
setup_td: uhci_td | t.CPtr = tds
|
||||
_td_set_link(setup_td, t.CUInt32T(t.CUInt64T(tds) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(setup_td, ls, 8)
|
||||
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
|
||||
setup_td.buffer = t.CUInt32T(t.CUInt64T(setup_buf))
|
||||
|
||||
if data_len > 0:
|
||||
data_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
|
||||
_td_set_link(data_td, t.CUInt32T(t.CUInt64T(data_td) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(data_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
else:
|
||||
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
data_td.buffer = t.CUInt32T(t.CUInt64T(data_buf))
|
||||
|
||||
status_td: uhci_td | t.CPtr = t.CUInt64T(data_td) + uhci_td.__sizeof__()
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
else:
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
else:
|
||||
status_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
|
||||
_qh_set_element(_ctrl_qh, t.CUInt32T(t.CUInt64T(setup_td)), 0)
|
||||
|
||||
result: t.CInt = _wait_for_complete(status_td, 500)
|
||||
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
mm.free(tds)
|
||||
return result
|
||||
330
VKernel/Kernel/drivers/usb/usb.py
Normal file
330
VKernel/Kernel/drivers/usb/usb.py
Normal file
@@ -0,0 +1,330 @@
|
||||
import t, c
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.usb.pci as pci
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
|
||||
USB_DESC_DEVICE: t.CDefine = 1
|
||||
USB_DESC_CONFIG: t.CDefine = 2
|
||||
USB_DESC_STRING: t.CDefine = 3
|
||||
USB_DESC_INTERFACE: t.CDefine = 4
|
||||
USB_DESC_ENDPOINT: t.CDefine = 5
|
||||
|
||||
USB_REQ_GET_STATUS: t.CDefine = 0
|
||||
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
|
||||
USB_REQ_SET_FEATURE: t.CDefine = 3
|
||||
USB_REQ_SET_ADDRESS: t.CDefine = 5
|
||||
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
|
||||
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
|
||||
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
|
||||
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
|
||||
|
||||
USB_REQ_SET_INTERFACE: t.CDefine = 11
|
||||
|
||||
HID_CLASS: t.CDefine = 0x03
|
||||
HID_SUBCLASS_BOOT: t.CDefine = 0x01
|
||||
HID_PROTO_KEYBOARD: t.CDefine = 0x01
|
||||
HID_PROTO_MOUSE: t.CDefine = 0x02
|
||||
|
||||
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
|
||||
HID_REQ_SET_IDLE: t.CDefine = 0x0A
|
||||
HID_REQ_GET_REPORT: t.CDefine = 0x01
|
||||
|
||||
USB_MAX_DEVICES: t.CDefine = 8
|
||||
|
||||
class usb_dev_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bcdUSB: t.CUInt16T
|
||||
bDeviceClass: t.CUInt8T
|
||||
bDeviceSubClass: t.CUInt8T
|
||||
bDeviceProtocol: t.CUInt8T
|
||||
bMaxPacketSize0: t.CUInt8T
|
||||
idVendor: t.CUInt16T
|
||||
idProduct: t.CUInt16T
|
||||
bcdDevice: t.CUInt16T
|
||||
iManufacturer: t.CUInt8T
|
||||
iProduct: t.CUInt8T
|
||||
iSerialNumber: t.CUInt8T
|
||||
bNumConfigurations: t.CUInt8T
|
||||
|
||||
class usb_config_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
wTotalLength: t.CUInt16T
|
||||
bNumInterfaces: t.CUInt8T
|
||||
bConfigurationValue: t.CUInt8T
|
||||
iConfiguration: t.CUInt8T
|
||||
bmAttributes: t.CUInt8T
|
||||
bMaxPower: t.CUInt8T
|
||||
|
||||
class usb_iface_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bInterfaceNumber: t.CUInt8T
|
||||
bAlternateSetting: t.CUInt8T
|
||||
bNumEndpoints: t.CUInt8T
|
||||
bInterfaceClass: t.CUInt8T
|
||||
bInterfaceSubClass: t.CUInt8T
|
||||
bInterfaceProtocol: t.CUInt8T
|
||||
iInterface: t.CUInt8T
|
||||
|
||||
class usb_ep_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bEndpointAddress: t.CUInt8T
|
||||
bmAttributes: t.CUInt8T
|
||||
wMaxPacketSize: t.CUInt16T
|
||||
bInterval: t.CUInt8T
|
||||
|
||||
class usb_setup_pkt(t.CStruct):
|
||||
bmRequestType: t.CUInt8T
|
||||
bRequest: t.CUInt8T
|
||||
wValue: t.CUInt16T
|
||||
wIndex: t.CUInt16T
|
||||
wLength: t.CUInt16T
|
||||
|
||||
class usb_device(t.CStruct):
|
||||
addr: t.CUInt8T
|
||||
ls: t.CInt
|
||||
max_pkt0: t.CUInt8T
|
||||
iface_class: t.CUInt8T
|
||||
iface_subclass: t.CUInt8T
|
||||
iface_protocol: t.CUInt8T
|
||||
iface_num: t.CUInt8T
|
||||
ep_in: t.CUInt8T
|
||||
ep_in_max: t.CUInt16T
|
||||
ep_in_interval: t.CUInt8T
|
||||
ep_in_toggle: t.CUInt8T
|
||||
configured: t.CInt
|
||||
|
||||
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
|
||||
_device_count: t.CInt = 0
|
||||
|
||||
def _setup_packet(bmRequestType: t.CUInt8T, bRequest: t.CUInt8T, wValue: t.CUInt16T, wIndex: t.CUInt16T, wLength: t.CUInt16T, buf: usb_setup_pkt | t.CPtr):
|
||||
buf.bmRequestType = bmRequestType
|
||||
buf.bRequest = bRequest
|
||||
buf.wValue = wValue
|
||||
buf.wIndex = wIndex
|
||||
buf.wLength = wLength
|
||||
|
||||
def _send_control(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup: usb_setup_pkt | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
|
||||
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
|
||||
|
||||
def get_descriptor(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, desc_type: t.CUInt8T, desc_idx: t.CUInt8T, buf: t.CVoid | t.CPtr, length: t.CUInt16T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (t.CUInt16T(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
|
||||
|
||||
def set_address(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, new_addr: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def set_configuration(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, config_val: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_protocol(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, protocol: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, t.CUInt16T(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_idle(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, duration: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_IDLE, t.CUInt16T(duration) << 8, t.CUInt16T(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CVoid | t.CPtr, total_len: t.CUInt16T):
|
||||
offset: t.CInt = 0
|
||||
found_hid: t.CInt = 0
|
||||
while offset < t.CInt(total_len):
|
||||
p: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
desc_len: t.CUInt8T = c.Deref(p)
|
||||
p2: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) + 1
|
||||
desc_type: t.CUInt8T = c.Deref(p2)
|
||||
if desc_len == 0: break
|
||||
if desc_type == USB_DESC_INTERFACE:
|
||||
iface: usb_iface_desc | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
if iface.bInterfaceClass == HID_CLASS:
|
||||
found_hid = 1
|
||||
dev.iface_class = HID_CLASS
|
||||
dev.iface_subclass = iface.bInterfaceSubClass
|
||||
dev.iface_protocol = iface.bInterfaceProtocol
|
||||
dev.iface_num = iface.bInterfaceNumber
|
||||
if desc_type == USB_DESC_ENDPOINT and found_hid:
|
||||
ep: usb_ep_desc | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
if (ep.bEndpointAddress & 0x80) != 0:
|
||||
dev.ep_in = ep.bEndpointAddress & 0x0F
|
||||
dev.ep_in_max = ep.wMaxPacketSize
|
||||
dev.ep_in_interval = ep.bInterval
|
||||
found_hid = 0
|
||||
offset = offset + t.CInt(desc_len)
|
||||
|
||||
def enumerate_port(port: t.CInt) -> t.CInt:
|
||||
global _device_count
|
||||
if _device_count >= USB_MAX_DEVICES: return -1
|
||||
|
||||
ls: t.CInt = uhci.port_is_low_speed(port)
|
||||
|
||||
reset_ok: t.CInt = -1
|
||||
reset_retry: t.CInt
|
||||
for reset_retry in range(3):
|
||||
if uhci.port_reset(port) == 0:
|
||||
reset_ok = 0
|
||||
break
|
||||
timer.timer_msleep(50)
|
||||
if reset_ok != 0:
|
||||
return -2
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev_buf: t.CVoid | t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
|
||||
if dev_buf is None: return -3
|
||||
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
|
||||
|
||||
result: t.CInt = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
retry: t.CInt
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
uhci.port_reset(port)
|
||||
timer.timer_msleep(10)
|
||||
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -4
|
||||
|
||||
desc: usb_dev_desc | t.CPtr = dev_buf
|
||||
max_pkt: t.CUInt8T = desc.bMaxPacketSize0
|
||||
if max_pkt < 8: max_pkt = 8
|
||||
|
||||
new_addr: t.CUInt8T = t.CUInt8T(_device_count + 1)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(20)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -5
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
|
||||
dev.addr = new_addr
|
||||
dev.ls = ls
|
||||
dev.max_pkt0 = max_pkt
|
||||
dev.configured = 0
|
||||
dev.iface_class = 0
|
||||
dev.iface_subclass = 0
|
||||
dev.iface_protocol = 0
|
||||
dev.ep_in = 0
|
||||
dev.ep_in_max = 0
|
||||
dev.ep_in_interval = 0
|
||||
dev.ep_in_toggle = 0
|
||||
|
||||
config_buf: t.CVoid | t.CPtr = mm.malloc(256)
|
||||
if config_buf is None:
|
||||
mm.free(dev_buf)
|
||||
return -6
|
||||
string.memset(config_buf, 0, 256)
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -7
|
||||
|
||||
cfg: usb_config_desc | t.CPtr = config_buf
|
||||
total_len: t.CUInt16T = cfg.wTotalLength
|
||||
if total_len > 256: total_len = 256
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -8
|
||||
|
||||
_parse_config(dev, config_buf, total_len)
|
||||
|
||||
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -9
|
||||
|
||||
dev.configured = 1
|
||||
|
||||
if dev.iface_class == HID_CLASS:
|
||||
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
|
||||
_device_count = _device_count + 1
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return t.CInt(new_addr)
|
||||
|
||||
def init() -> t.CInt:
|
||||
global _device_count
|
||||
_device_count = 0
|
||||
|
||||
io_base: t.CUInt16T = pci.find_uhci()
|
||||
if io_base == 0:
|
||||
serial.puts("[usb] UHCI controller not found\n")
|
||||
return -1
|
||||
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", t.CUInt32T(io_base))
|
||||
serial.puts(buf)
|
||||
|
||||
if uhci.init(io_base) != 0:
|
||||
serial.puts("[usb] UHCI init failed\n")
|
||||
return -2
|
||||
|
||||
serial.puts("[usb] UHCI initialized\n")
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
port: t.CInt
|
||||
for port in range(2):
|
||||
if uhci.port_is_connected(port):
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", t.CUInt32T(port))
|
||||
serial.puts(buf)
|
||||
dev_id: t.CInt = enumerate_port(port)
|
||||
if dev_id > 0:
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
|
||||
t.CUInt32T(dev.addr), t.CUInt32T(dev.iface_class),
|
||||
t.CUInt32T(dev.iface_protocol), t.CUInt32T(dev.ep_in))
|
||||
serial.puts(buf)
|
||||
else:
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", t.CUInt32T(port), t.CInt32T(dev_id))
|
||||
serial.puts(buf)
|
||||
|
||||
return _device_count
|
||||
|
||||
def find_hid_device(protocol: t.CUInt8T) -> usb_device | t.CPtr:
|
||||
i: t.CInt
|
||||
for i in range(_device_count):
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[i])
|
||||
if dev.iface_class == HID_CLASS:
|
||||
if dev.iface_protocol == protocol:
|
||||
if dev.configured != 0:
|
||||
return dev
|
||||
return None
|
||||
|
||||
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return 0
|
||||
85
VKernel/Kernel/drivers/video/ui/sheet.py
Normal file
85
VKernel/Kernel/drivers/video/ui/sheet.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from stdint import *
|
||||
import drivers.video.vesafb.gfx as gfx
|
||||
import t, c
|
||||
|
||||
MAX_SHEETS: t.CDefine = 64
|
||||
MAX_UI_COMPONENTS: t.CDefine = 256
|
||||
|
||||
_next_sheet_id: t.CInt = 0
|
||||
_next_component_id: t.CInt = 0
|
||||
|
||||
@t.Object
|
||||
class Sheet:
|
||||
id: t.CInt
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
w: t.CInt
|
||||
h: t.CInt
|
||||
visible: t.CInt
|
||||
_surf_obj: gfx.Surface
|
||||
_renderer_obj: gfx.Renderer
|
||||
surf: gfx.Surface | t.CPtr
|
||||
renderer: gfx.Renderer | t.CPtr
|
||||
parent: 'Sheet | t.CPtr'
|
||||
bg_color: t.CUInt32T
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, parent: 'Sheet | t.CPtr' = None):
|
||||
global _next_sheet_id
|
||||
self.id = _next_sheet_id
|
||||
_next_sheet_id += 1
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.visible = 1
|
||||
self._surf_obj = gfx.Surface(fb, zb, w, h)
|
||||
self.surf = c.Addr(self._surf_obj)
|
||||
self._renderer_obj = gfx.Renderer(self.surf)
|
||||
self.renderer = c.Addr(self._renderer_obj)
|
||||
self.parent = parent
|
||||
self.bg_color = gfx.COLOR_RGB(20, 20, 30)
|
||||
|
||||
def MoveTo(self, nx: t.CInt, ny: t.CInt):
|
||||
self.x = nx
|
||||
self.y = ny
|
||||
|
||||
def Resize(self, nw: t.CInt, nh: t.CInt):
|
||||
self.w = nw
|
||||
self.h = nh
|
||||
|
||||
def Show(self):
|
||||
self.visible = 1
|
||||
|
||||
def Hide(self):
|
||||
self.visible = 0
|
||||
|
||||
def Clear(self):
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.Clear(self.bg_color)
|
||||
|
||||
def Fill(self, color: t.CUInt32T):
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.Clear(color)
|
||||
|
||||
def DrawRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.DrawLine2D(rx, ry, rx + rw - 1, ry, color)
|
||||
r.DrawLine2D(rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
|
||||
r.DrawLine2D(rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
|
||||
r.DrawLine2D(rx, ry + rh - 1, rx, ry, color)
|
||||
|
||||
def DrawFilledRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
|
||||
surf: gfx.Surface = c.Deref(self.surf)
|
||||
fb: UINT32PTR = surf.fb
|
||||
w: t.CInt = surf.w
|
||||
h: t.CInt = surf.h
|
||||
for py in range(ry, ry + rh):
|
||||
if py < 0 or py >= h: continue
|
||||
for px in range(rx, rx + rw):
|
||||
if px < 0 or px >= w: continue
|
||||
fb[py * w + px] = color
|
||||
|
||||
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
|
||||
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
|
||||
return 1
|
||||
return 0
|
||||
152
VKernel/Kernel/drivers/video/ui/ui.py
Normal file
152
VKernel/Kernel/drivers/video/ui/ui.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from stdint import *
|
||||
import drivers.video.vesafb.gfx as gfx
|
||||
import drivers.video.ui.sheet as sheet
|
||||
import string
|
||||
import t, c
|
||||
|
||||
UI_LABEL: t.CDefine = 0
|
||||
UI_BUTTON: t.CDefine = 1
|
||||
UI_PANEL: t.CDefine = 2
|
||||
UI_PROGRESS: t.CDefine = 3
|
||||
|
||||
@t.Object
|
||||
class UIComponent:
|
||||
id: t.CInt
|
||||
ctype: t.CInt
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
w: t.CInt
|
||||
h: t.CInt
|
||||
visible: t.CInt
|
||||
sheet: sheet.Sheet | t.CPtr
|
||||
fg_color: t.CUInt32T
|
||||
bg_color: t.CUInt32T
|
||||
text: t.CArray[t.CChar, 128]
|
||||
text_len: t.CInt
|
||||
value: t.CInt
|
||||
|
||||
def __init__(self, ctype: t.CInt, sh: sheet.Sheet | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
|
||||
global _next_component_id
|
||||
self.id = _next_component_id
|
||||
_next_component_id += 1
|
||||
self.ctype = ctype
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.visible = 1
|
||||
self.sheet = sh
|
||||
self.fg_color = gfx.COLOR_RGB(255, 255, 255)
|
||||
self.bg_color = gfx.COLOR_RGB(40, 40, 60)
|
||||
string.memset(c.Addr(self.text), 0, 128)
|
||||
self.text_len = 0
|
||||
self.value = 0
|
||||
|
||||
def SetText(self, s: str):
|
||||
i: t.CInt = 0
|
||||
for ch in s:
|
||||
if i >= 127: break
|
||||
self.text[i] = ch
|
||||
i += 1
|
||||
self.text[i] = 0
|
||||
self.text_len = i
|
||||
|
||||
def SetValue(self, v: t.CInt):
|
||||
self.value = v
|
||||
|
||||
def Render(self):
|
||||
if self.visible == 0: return
|
||||
sh: sheet.Sheet = c.Deref(self.sheet)
|
||||
match self.ctype:
|
||||
case 0:
|
||||
self._RenderLabel(sh)
|
||||
case 1:
|
||||
self._RenderButton(sh)
|
||||
case 2:
|
||||
self._RenderPanel(sh)
|
||||
case 3:
|
||||
self._RenderProgress(sh)
|
||||
|
||||
def _RenderLabel(self, sh: sheet.Sheet):
|
||||
sh.DrawFilledRect(self.x, self.y, self.w, self.h, 0)
|
||||
|
||||
def _RenderButton(self, sh: sheet.Sheet):
|
||||
sh.DrawFilledRect(self.x, self.y, self.w, self.h, self.bg_color)
|
||||
sh.DrawRect(self.x, self.y, self.w, self.h, self.fg_color)
|
||||
|
||||
def _RenderPanel(self, sh: sheet.Sheet):
|
||||
sh.DrawFilledRect(self.x, self.y, self.w, self.h, self.bg_color)
|
||||
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 120))
|
||||
|
||||
def _RenderProgress(self, sh: sheet.Sheet):
|
||||
sh.DrawFilledRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(30, 30, 40))
|
||||
fill_w: t.CInt = self.w * self.value / 100
|
||||
if fill_w > 0:
|
||||
sh.DrawFilledRect(self.x, self.y, fill_w, self.h, gfx.COLOR_RGB(0, 180, 255))
|
||||
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 100))
|
||||
|
||||
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
|
||||
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@t.Object
|
||||
class UIManager:
|
||||
sheets: t.CArray[sheet.Sheet | t.CPtr, 64]
|
||||
sheet_count: t.CInt
|
||||
components: t.CArray[UIComponent | t.CPtr, 256]
|
||||
component_count: t.CInt
|
||||
screen_w: t.CInt
|
||||
screen_h: t.CInt
|
||||
|
||||
def __init__(self, w: t.CInt, h: t.CInt):
|
||||
self.sheet_count = 0
|
||||
self.component_count = 0
|
||||
self.screen_w = w
|
||||
self.screen_h = h
|
||||
i: t.CInt
|
||||
for i in range(64):
|
||||
self.sheets[i] = None
|
||||
for i in range(256):
|
||||
self.components[i] = None
|
||||
|
||||
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> t.CInt:
|
||||
if self.sheet_count >= 64: return -1
|
||||
self.sheets[self.sheet_count] = sh
|
||||
self.sheet_count += 1
|
||||
return 0
|
||||
|
||||
def AddComponent(self, comp: UIComponent | t.CPtr) -> t.CInt:
|
||||
if self.component_count >= 256: return -1
|
||||
self.components[self.component_count] = comp
|
||||
self.component_count += 1
|
||||
return 0
|
||||
|
||||
def FindComponent(self, cid: t.CInt) -> UIComponent | t.CPtr:
|
||||
i: t.CInt
|
||||
for i in range(self.component_count):
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
comp: UIComponent = c.Deref(p)
|
||||
if comp.id == cid: return p
|
||||
return None
|
||||
|
||||
def RenderAll(self):
|
||||
i: t.CInt
|
||||
for i in range(self.component_count):
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
comp: UIComponent = c.Deref(p)
|
||||
comp.Render()
|
||||
|
||||
def HitTest(self, px: t.CInt, py: t.CInt) -> UIComponent | t.CPtr:
|
||||
i: t.CInt = self.component_count - 1
|
||||
while i >= 0:
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
comp: UIComponent = c.Deref(p)
|
||||
if comp.visible == 1 and comp.Contains(px, py) == 1:
|
||||
return p
|
||||
i -= 1
|
||||
return None
|
||||
305
VKernel/Kernel/drivers/video/vesafb/gfx.py
Normal file
305
VKernel/Kernel/drivers/video/vesafb/gfx.py
Normal file
@@ -0,0 +1,305 @@
|
||||
from stdint import *
|
||||
import vipermath
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
PI: t.CDefine = float(3.14159265358979323846)
|
||||
|
||||
SPHERE_SLICES: t.CDefine = (24 * 1)
|
||||
SPHERE_STACKS: t.CDefine = (16 * 1)
|
||||
SIN_WAVE_GRID: t.CDefine = (40 * 1)
|
||||
|
||||
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
|
||||
return (255 << 24) | (r << 16) | (g << 8) | (b)
|
||||
|
||||
@t.Object
|
||||
class Vec3:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
def __init__(self, x: float, y: float, z: float):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
def Sub(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
|
||||
def Cross(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
|
||||
def Dot(self, b: 'Vec3') -> float:
|
||||
return self.x * b.x + self.y * b.y + self.z * b.z
|
||||
def Norm(self) -> 'Vec3':
|
||||
l = vipermath.sqrtf(self.Dot(self))
|
||||
return Vec3(self.x / l, self.y / l, self.z / l)
|
||||
|
||||
class Mat4:
|
||||
m: t.CArray[t.CArray[float, 4], 4]
|
||||
|
||||
def Mat4_Identity() -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
|
||||
res: Mat4 = Mat4()
|
||||
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
for k in range(4):
|
||||
res.m[i][j] += a.m[i][k] * b.m[k][j]
|
||||
return res
|
||||
|
||||
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
|
||||
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
|
||||
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
|
||||
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
|
||||
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
|
||||
if w != 0:
|
||||
x /= w; y /= w; z /= w
|
||||
return Vec3(x, y, z)
|
||||
|
||||
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
|
||||
m.m[0][0] = f / aspect; m.m[1][1] = f
|
||||
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
|
||||
return m
|
||||
|
||||
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
|
||||
zaxis: Vec3 = eye.Sub(target).Norm()
|
||||
xaxis: Vec3 = up.Cross(zaxis).Norm()
|
||||
yaxis: Vec3 = zaxis.Cross(xaxis)
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
|
||||
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
|
||||
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
|
||||
m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
|
||||
return m
|
||||
|
||||
def Mat4_RotateY(a: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity();
|
||||
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
|
||||
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
|
||||
return m
|
||||
|
||||
|
||||
@t.Object
|
||||
class Surface:
|
||||
fb: UINT32PTR
|
||||
zb: float | t.CPtr
|
||||
w: int
|
||||
h: int
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.fb = fb
|
||||
self.zb = zb
|
||||
self.w = w
|
||||
self.h = h
|
||||
|
||||
@t.Object
|
||||
class Renderer:
|
||||
_fb: UINT32PTR
|
||||
_zb: float | t.CPtr
|
||||
_w: int
|
||||
_h: int
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self._fb = fb
|
||||
self._zb = zb
|
||||
self._w = w
|
||||
self._h = h
|
||||
|
||||
def Clear(self, color: t.CUInt32T):
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
size: int = self._w * self._h
|
||||
for i in range(size):
|
||||
fb[i] = color
|
||||
zb[i] = float(1.0)
|
||||
|
||||
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
|
||||
fb: UINT32PTR = self._fb
|
||||
w: int = self._w; h: int = self._h
|
||||
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
|
||||
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
|
||||
err: int = dx - dy
|
||||
while True:
|
||||
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
|
||||
if x0 == x1 and y0 == y1: break
|
||||
e2: int = 2 * err
|
||||
if e2 > -dy: err -= dy; x0 += sx
|
||||
if e2 < dx: err += dx; y0 += sy
|
||||
|
||||
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
|
||||
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
|
||||
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
|
||||
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
|
||||
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
|
||||
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
w: int = self._w
|
||||
h: int = self._h
|
||||
|
||||
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
|
||||
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
|
||||
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
|
||||
|
||||
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
|
||||
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
|
||||
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
|
||||
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
|
||||
|
||||
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
|
||||
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
|
||||
denom: float = dx12 * dy02 - dy12 * dx02
|
||||
if denom < float(0.001) and denom > float(-0.001): return
|
||||
invDenom: float = float(1.0) / denom
|
||||
|
||||
row_dxP_start: float = float(minX) - sx2
|
||||
for y in range(minY, maxY + 1):
|
||||
dyP: float = float(y) - sy2
|
||||
dxP: float = row_dxP_start
|
||||
row_base: int = y * w
|
||||
for x in range(minX, maxX + 1):
|
||||
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
|
||||
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
|
||||
w2: float = float(1.0) - w0 - w1
|
||||
if w0 >= 0 and w1 >= 0 and w2 >= 0:
|
||||
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
|
||||
idx: int = row_base + x
|
||||
if z < zb[idx]:
|
||||
zb[idx] = z
|
||||
fb[idx] = col
|
||||
dxP += float(1.0)
|
||||
|
||||
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
r: int = int(radius) + 4
|
||||
ix: int = int(x); iy: int = int(y)
|
||||
for dy in range(-r, r + 1):
|
||||
py: int = iy + dy
|
||||
if py < 0 or py >= h: continue
|
||||
for dx in range(-r, r + 1):
|
||||
px: int = ix + dx
|
||||
if px < 0 or px >= w: continue
|
||||
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
|
||||
if dist < radius:
|
||||
self.BlendPixel(px, py, core_col, intensity)
|
||||
elif dist < float(r):
|
||||
fade: float = 1.0 - (dist - radius) / 4.0
|
||||
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
|
||||
|
||||
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
|
||||
if alpha <= 0.0: return
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
if x < 0 or x >= w or y < 0 or y >= h: return
|
||||
|
||||
idx: int = y * w + x
|
||||
bg: t.CUInt32T = fb[idx]
|
||||
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
|
||||
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
|
||||
|
||||
a: int = int(alpha * 255.0)
|
||||
inv_a: int = 255 - a
|
||||
nr: int = (f_r * a + bg_r * inv_a) >> 8
|
||||
ng: int = (f_g * a + bg_g * inv_a) >> 8
|
||||
nb: int = (f_b * a + bg_b * inv_a) >> 8
|
||||
|
||||
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
|
||||
255 if (ng > 255) else ng,
|
||||
255 if (nb > 255) else nb)
|
||||
|
||||
|
||||
@t.Object
|
||||
class Scene3D:
|
||||
renderer: Renderer
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.renderer = Renderer(fb, zb, w, h)
|
||||
|
||||
def Render(self, time: float):
|
||||
rw: int = self.renderer._w
|
||||
rh: int = self.renderer._h
|
||||
self.renderer.Clear(COLOR_RGB(15, 15, 25))
|
||||
|
||||
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
|
||||
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
|
||||
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
|
||||
view: Mat4 = Mat4_LookAt(eye, target, up)
|
||||
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
|
||||
vp: Mat4 = Mat4_Mul(proj, view)
|
||||
|
||||
cubeX: float = float(-3.5)
|
||||
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
|
||||
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
|
||||
|
||||
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
|
||||
for i in range(4):
|
||||
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
|
||||
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
|
||||
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
|
||||
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
|
||||
|
||||
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
|
||||
|
||||
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
|
||||
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
|
||||
wave_shift: float = time * float(2.0)
|
||||
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
|
||||
for i in range(1, rw - 100):
|
||||
tr: float = float(i) / float(rw-100) * float(4.0) * PI
|
||||
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
|
||||
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
|
||||
prev_x = cx; prev_y = cy
|
||||
|
||||
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
|
||||
v: t.CArray[Vec3, 8] = [
|
||||
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
|
||||
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
|
||||
]
|
||||
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
|
||||
faces: t.CArray[t.CArray[int, 3], 12] = [
|
||||
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
|
||||
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
|
||||
]
|
||||
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
|
||||
|
||||
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
|
||||
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
|
||||
for i in range(SPHERE_STACKS):
|
||||
for j in range(SPHERE_SLICES):
|
||||
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
|
||||
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
|
||||
v: t.CArray[Vec3, 4]
|
||||
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
|
||||
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
|
||||
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
|
||||
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
|
||||
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
|
||||
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
|
||||
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
|
||||
|
||||
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
|
||||
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
|
||||
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
|
||||
for i in range(SIN_WAVE_GRID):
|
||||
for j in range(SIN_WAVE_GRID):
|
||||
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
|
||||
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
|
||||
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
|
||||
|
||||
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
|
||||
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
|
||||
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
|
||||
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
|
||||
|
||||
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
|
||||
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
|
||||
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)
|
||||
504
VKernel/Kernel/drivers/video/vesafb/vga.py
Normal file
504
VKernel/Kernel/drivers/video/vesafb/vga.py
Normal file
@@ -0,0 +1,504 @@
|
||||
import string # std: standard
|
||||
#import math # std: standard
|
||||
import t, c
|
||||
|
||||
|
||||
# 颜色格式枚举
|
||||
class __ColorFormat(t.CEnum):
|
||||
ColorFormat_BGRA: t.State # BGRA格式(蓝色、绿色、红色、Alpha)
|
||||
ColorFormat_RGBA: t.State # RGBA格式(红色、绿色、蓝色、Alpha)
|
||||
ColorFormat_BGR: t.State # BGR格式(蓝色、绿色、红色)
|
||||
ColorFormat_RGB: t.State # RGB格式(红色、绿色、蓝色)
|
||||
|
||||
# 常量定义 - 提升代码可读性和可维护性
|
||||
VGA_WIDTH: t.CDefine = 80
|
||||
VGA_HEIGHT: t.CDefine = 25
|
||||
FONT_WIDTH: t.CDefine = 8
|
||||
FONT_HEIGHT: t.CDefine = 16
|
||||
DEFAULT_CHAR: t.CDefine = 0 # 非ASCII字符的默认替换字符
|
||||
SERIAL_PORT: t.CDefine = 0x3F8 # 串口调试端口地址
|
||||
|
||||
# 8x16字符点阵字库 (每个字符16字节,共256个字符)
|
||||
font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
|
||||
# 字符编号 0x00 - 0x0F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x00
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x01
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x56, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x02
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x56, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x03
|
||||
{0x00, 0x00, 0x70, 0x55, 0x55, 0x57, 0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x04
|
||||
{0x00, 0x00, 0x70, 0x57, 0x54, 0x57, 0x71, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x05
|
||||
{0x00, 0x00, 0x70, 0x57, 0x54, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x06
|
||||
{0x00, 0x00, 0x70, 0x57, 0x51, 0x52, 0x72, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x07
|
||||
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x08
|
||||
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x71, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x09
|
||||
{0x00, 0x00, 0x70, 0x56, 0x51, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0A
|
||||
{0x00, 0x00, 0x70, 0x54, 0x54, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0B
|
||||
{0x00, 0x00, 0x70, 0x50, 0x50, 0x57, 0x74, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0C
|
||||
{0x00, 0x00, 0x70, 0x51, 0x51, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0D
|
||||
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0E
|
||||
{0x00, 0x00, 0x70, 0x53, 0x54, 0x56, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0F
|
||||
|
||||
# 字符编号 0x10 - 0x1F
|
||||
{0x00, 0x00, 0x10, 0x37, 0x15, 0x15, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x10
|
||||
{0x00, 0x00, 0x10, 0x32, 0x16, 0x12, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x11
|
||||
{0x00, 0x00, 0x20, 0x6E, 0x22, 0x2E, 0x28, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x12
|
||||
{0x00, 0x00, 0x10, 0x37, 0x11, 0x13, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x13
|
||||
{0x00, 0x00, 0x10, 0x35, 0x15, 0x17, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x14
|
||||
{0x00, 0x00, 0x10, 0x37, 0x14, 0x17, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x15
|
||||
{0x00, 0x00, 0x10, 0x37, 0x14, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x16
|
||||
{0x00, 0x00, 0x10, 0x37, 0x11, 0x12, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x17
|
||||
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x18
|
||||
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x19
|
||||
{0x00, 0x00, 0x10, 0x36, 0x11, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1A
|
||||
{0x00, 0x00, 0x10, 0x34, 0x14, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1B
|
||||
{0x00, 0x00, 0x10, 0x30, 0x10, 0x17, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1C
|
||||
{0x00, 0x00, 0x10, 0x31, 0x11, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1D
|
||||
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x14, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1E
|
||||
{0x00, 0x00, 0x10, 0x33, 0x14, 0x16, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1F
|
||||
|
||||
# 字符编号 0x20 - 0x2F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x20
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x21
|
||||
{0x6C, 0x6C, 0x6C, 0x6C, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x22
|
||||
{0x36, 0x36, 0x36, 0x7F, 0x7F, 0x36, 0x36, 0x36, 0x7F, 0x7F, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00}, # 0x23
|
||||
{0x0C, 0x0C, 0x3E, 0x7F, 0x68, 0x68, 0x3E, 0x0B, 0x0B, 0x7F, 0x3E, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x24
|
||||
{0x60, 0x60, 0x66, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x66, 0x06, 0x06, 0x00, 0x00, 0x00}, # 0x25
|
||||
{0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x38, 0x6C, 0x6D, 0x66, 0x66, 0x6F, 0x3B, 0x00, 0x00, 0x00}, # 0x26
|
||||
{0x18, 0x18, 0x18, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x27
|
||||
{0x1C, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x1C, 0x00, 0x00}, # 0x28
|
||||
{0x38, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x38, 0x00, 0x00}, # 0x29
|
||||
{0x00, 0x00, 0x18, 0x18, 0x7E, 0x3C, 0x3C, 0x3C, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2A
|
||||
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2B
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00}, # 0x2C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x2E
|
||||
{0x00, 0x00, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2F
|
||||
|
||||
# 字符编号 0x30 - 0x3F
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x6E, 0x6E, 0x7E, 0x76, 0x76, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x30
|
||||
{0x18, 0x38, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x31
|
||||
{0x3C, 0x7E, 0x66, 0x06, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x32
|
||||
{0x3C, 0x7E, 0x66, 0x06, 0x06, 0x1C, 0x1C, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x33
|
||||
{0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x2C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00}, # 0x34
|
||||
{0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7E, 0x06, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x35
|
||||
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x36
|
||||
{0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x37
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x38
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x39
|
||||
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x3A
|
||||
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00}, # 0x3B
|
||||
{0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x00, 0x00}, # 0x3C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x3D
|
||||
{0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00}, # 0x3E
|
||||
{0x3C, 0x7E, 0x66, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x3F
|
||||
|
||||
# 字符编号 0x40 - 0x4F
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x6E, 0x6A, 0x6A, 0x6A, 0x6E, 0x60, 0x60, 0x7C, 0x3C, 0x00, 0x00, 0x00}, # 0x40
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x41
|
||||
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, 0x00}, # 0x42
|
||||
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x43
|
||||
{0x78, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x7C, 0x78, 0x00, 0x00, 0x00}, # 0x44
|
||||
{0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x45
|
||||
{0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x46
|
||||
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x47
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x48
|
||||
{0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x49
|
||||
{0x3E, 0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x7C, 0x38, 0x00, 0x00, 0x00}, # 0x4A
|
||||
{0x66, 0x66, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x4B
|
||||
{0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x4C
|
||||
{0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0x4D
|
||||
{0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x4E
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x4F
|
||||
|
||||
# 字符编号 0x50 - 0x5F
|
||||
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x50
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6A, 0x6A, 0x6C, 0x7E, 0x36, 0x00, 0x00, 0x00}, # 0x51
|
||||
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x52
|
||||
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x78, 0x3C, 0x0E, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x53
|
||||
{0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x54
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x56
|
||||
{0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x77, 0x22, 0x00, 0x00, 0x00}, # 0x57
|
||||
{0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x58
|
||||
{0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x59
|
||||
{0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x5A
|
||||
{0x78, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x78, 0x00, 0x00}, # 0x5B
|
||||
{0xC0, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0x03, 0x00, 0x00, 0x00}, # 0x5C
|
||||
{0x1E, 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x1E, 0x00, 0x00}, # 0x5D
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x5E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00}, # 0x5F
|
||||
|
||||
# 字符编号 0x60 - 0x6F
|
||||
{0x30, 0x38, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x60
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x61
|
||||
{0x60, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, 0x00}, # 0x62
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x63
|
||||
{0x06, 0x06, 0x06, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x64
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x65
|
||||
{0x1C, 0x3E, 0x30, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x66
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x3E, 0x3C, 0x00}, # 0x67
|
||||
{0x60, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x68
|
||||
{0x18, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x69
|
||||
{0x0C, 0x0C, 0x00, 0x00, 0x3C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78, 0x00}, # 0x6A
|
||||
{0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x6B
|
||||
{0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x6C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0x6D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x6E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x6F
|
||||
|
||||
# 字符编号 0x70 - 0x7F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00}, # 0x70
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x07, 0x07, 0x00}, # 0x71
|
||||
{0x00, 0x00, 0x00, 0x00, 0x6C, 0x7E, 0x76, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x72
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x62, 0x70, 0x3C, 0x0E, 0x46, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x73
|
||||
{0x30, 0x30, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x1C, 0x00, 0x00, 0x00}, # 0x74
|
||||
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x75
|
||||
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x76
|
||||
{0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x7F, 0x36, 0x00, 0x00, 0x00}, # 0x77
|
||||
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x78
|
||||
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0x79
|
||||
{0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x7A
|
||||
{0x0E, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00}, # 0x7B
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, # 0x7C
|
||||
{0x70, 0x78, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x78, 0x70, 0x00, 0x00}, # 0x7D
|
||||
{0x31, 0x79, 0x6B, 0x4F, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x7E
|
||||
{0x00, 0x00, 0x70, 0x13, 0x24, 0x26, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x7F
|
||||
|
||||
# 字符编号 0x80 - 0x8F
|
||||
{0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x06, 0x06, 0x66, 0x7C, 0x3C, 0x1C, 0x0C, 0x00, 0x00, 0x00}, # 0x80
|
||||
{0x1C, 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x7F, 0x77, 0x22, 0x00, 0x00, 0x00}, # 0x81
|
||||
{0x1C, 0x36, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00, 0x00, 0x00}, # 0x82
|
||||
{0xFE, 0x92, 0x92, 0x92, 0x92, 0x92, 0xF2, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, 0x00}, # 0x83
|
||||
{0x66, 0x66, 0x99, 0x99, 0x81, 0x42, 0x42, 0x42, 0x81, 0x99, 0x99, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x84
|
||||
{0x18, 0x3C, 0x66, 0x00, 0x42, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x85
|
||||
{0x18, 0x3C, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0x86
|
||||
{0x07, 0x01, 0x01, 0x01, 0x02, 0x02, 0x64, 0x94, 0x94, 0x90, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, # 0x87
|
||||
{0x18, 0x28, 0x28, 0x48, 0x4F, 0x81, 0x81, 0x81, 0x4F, 0x48, 0x28, 0x28, 0x18, 0x00, 0x00, 0x00}, # 0x88
|
||||
{0x18, 0x14, 0x14, 0x12, 0xF2, 0x81, 0x81, 0x81, 0xF2, 0x12, 0x14, 0x14, 0x18, 0x00, 0x00, 0x00}, # 0x89
|
||||
{0x3C, 0x24, 0x24, 0x24, 0x24, 0x24, 0xE7, 0x81, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00}, # 0x8A
|
||||
{0x18, 0x24, 0x24, 0x42, 0x42, 0x81, 0xE7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x3C, 0x00, 0x00, 0x00}, # 0x8B
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00}, # 0x8C
|
||||
{0x45, 0x4B, 0x51, 0x61, 0x61, 0x61, 0x51, 0x49, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x8D
|
||||
{0xC0, 0xC0, 0xCC, 0x0C, 0x18, 0x18, 0x30, 0x60, 0x60, 0xC0, 0xDB, 0x1B, 0x1B, 0x00, 0x00, 0x00}, # 0x8E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x8F
|
||||
|
||||
# 字符编号 0x90 - 0x9F
|
||||
{0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x90
|
||||
{0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x91
|
||||
{0x00, 0x00, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x00, 0x00, 0x00}, # 0x92
|
||||
{0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x93
|
||||
{0x1B, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x94
|
||||
{0x36, 0x36, 0x36, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x95
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x6C, 0x6C}, # 0x96
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x97
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x98
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x99
|
||||
{0x77, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xFF, 0x77, 0x00, 0x00, 0x00}, # 0x9A
|
||||
{0x00, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xDB, 0xDB, 0xDF, 0xD8, 0xD8, 0xFF, 0x6E, 0x00, 0x00, 0x00}, # 0x9B
|
||||
{0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, # 0x9C
|
||||
{0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, # 0x9D
|
||||
{0x3C, 0x7C, 0x60, 0x66, 0x66, 0xF0, 0xF6, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x9E
|
||||
{0x3E, 0x7E, 0x66, 0x66, 0x66, 0xF6, 0xF6, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x9F
|
||||
|
||||
# 字符编号 0xA0 - 0xAF
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xA0
|
||||
{0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA1
|
||||
{0x08, 0x08, 0x3E, 0x7F, 0x6B, 0x68, 0x68, 0x68, 0x6B, 0x7F, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00}, # 0xA2
|
||||
{0x1C, 0x3E, 0x36, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xA3
|
||||
{0x00, 0x00, 0x42, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x66, 0x42, 0x00, 0x00, 0x00}, # 0xA4
|
||||
{0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA5
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA6
|
||||
{0x3C, 0x7E, 0x60, 0x78, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x1E, 0x06, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xA7
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xA8
|
||||
{0x3C, 0x42, 0x42, 0x81, 0x99, 0xA5, 0xA1, 0xA1, 0xA1, 0xA5, 0x99, 0x81, 0x42, 0x42, 0x3C, 0x00}, # 0xA9
|
||||
{0x1C, 0x1E, 0x06, 0x06, 0x1E, 0x36, 0x36, 0x3E, 0x1E, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xAA
|
||||
{0x00, 0x00, 0x33, 0x33, 0x66, 0x66, 0xCC, 0xCC, 0xCC, 0x66, 0x66, 0x33, 0x33, 0x00, 0x00, 0x00}, # 0xAB
|
||||
{0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAC
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAD
|
||||
{0x3C, 0x42, 0x42, 0x81, 0xB9, 0xA5, 0xA5, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, 0x42, 0x42, 0x3C, 0x00}, # 0xAE
|
||||
{0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAF
|
||||
|
||||
# 字符编号 0xB0 - 0xBF
|
||||
{0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB0
|
||||
{0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00}, # 0xB1
|
||||
{0x38, 0x04, 0x04, 0x04, 0x18, 0x20, 0x20, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB2
|
||||
{0x38, 0x04, 0x04, 0x04, 0x18, 0x04, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB3
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB4
|
||||
{0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x3E, 0x30, 0x60, 0x60}, # 0xB5
|
||||
{0x03, 0x03, 0x3E, 0x7E, 0x76, 0x76, 0x76, 0x36, 0x36, 0x36, 0x36, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xB6
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB7
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x30, 0x00}, # 0xB8
|
||||
{0x10, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB9
|
||||
{0x1C, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xBA
|
||||
{0x00, 0x00, 0x88, 0xCC, 0x66, 0x66, 0x33, 0x33, 0x33, 0x66, 0x66, 0xCC, 0x88, 0x00, 0x00, 0x00}, # 0xBB
|
||||
{0x40, 0x40, 0xC0, 0x40, 0x40, 0x40, 0x48, 0x48, 0x48, 0x08, 0x0A, 0x0A, 0x0F, 0x02, 0x02, 0x00}, # 0xBC
|
||||
{0x40, 0x40, 0xC0, 0x40, 0x40, 0x40, 0x4F, 0x41, 0x41, 0x01, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x00}, # 0xBD
|
||||
{0xE0, 0x20, 0x20, 0x20, 0xE0, 0x20, 0x28, 0x28, 0xE8, 0x08, 0x0A, 0x0A, 0x0F, 0x02, 0x02, 0x00}, # 0xBE
|
||||
{0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x30, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xBF
|
||||
|
||||
# 字符编号 0xC0 - 0xCF
|
||||
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC0
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC1
|
||||
{0x18, 0x3C, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC2
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC3
|
||||
{0x66, 0x66, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC4
|
||||
{0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC5
|
||||
{0x3F, 0x7F, 0x6C, 0x6C, 0x6C, 0x7F, 0x7F, 0x6C, 0x6C, 0x6C, 0x6C, 0x6F, 0x6F, 0x00, 0x00, 0x00}, # 0xC6
|
||||
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x18, 0x30, 0x30, 0x60, 0x00}, # 0xC7
|
||||
{0x30, 0x38, 0x18, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xC8
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xC9
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCA
|
||||
{0x66, 0x66, 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCB
|
||||
{0x30, 0x38, 0x18, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCC
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCD
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCE
|
||||
{0x66, 0x66, 0x66, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCF
|
||||
|
||||
# 字符编号 0xD0 - 0xDF
|
||||
{0x78, 0x7C, 0x6C, 0x66, 0x66, 0xF6, 0xF6, 0x66, 0x66, 0x66, 0x6C, 0x7C, 0x78, 0x00, 0x00, 0x00}, # 0xD0
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x66, 0x66, 0x76, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xD1
|
||||
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD2
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD3
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD4
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD5
|
||||
{0x66, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD6
|
||||
{0x00, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x36, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0xD7
|
||||
{0x3D, 0x7F, 0x66, 0x66, 0x6E, 0x6E, 0x7E, 0x76, 0x76, 0x66, 0x66, 0x7E, 0xBC, 0x80, 0x00, 0x00}, # 0xD8
|
||||
{0x30, 0x38, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD9
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDA
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDB
|
||||
{0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDC
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xDD
|
||||
{0xF0, 0xF0, 0x60, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x78, 0x60, 0xF0, 0xF0, 0x00, 0x00, 0x00}, # 0xDE
|
||||
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x6C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x6E, 0x6C, 0x60, 0xC0, 0x00}, # 0xDF
|
||||
|
||||
# 字符编号 0xE0 - 0xEF
|
||||
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE0
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE1
|
||||
{0x18, 0x3C, 0x66, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE2
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE3
|
||||
{0x66, 0x66, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE4
|
||||
{0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE5
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x3F, 0x0B, 0x3B, 0x7F, 0x6F, 0x68, 0x7F, 0x3F, 0x00, 0x00, 0x00}, # 0xE6
|
||||
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x10, 0x60, 0x00}, # 0xE7
|
||||
{0x30, 0x38, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE8
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE9
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xEA
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xEB
|
||||
{0x30, 0x38, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEC
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xED
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEE
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEF
|
||||
|
||||
# 字符编号 0xF0 - 0xFF
|
||||
{0x18, 0x18, 0x7E, 0x7E, 0x0C, 0x06, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF0
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xF1
|
||||
{0x30, 0x38, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF2
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF3
|
||||
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF4
|
||||
{0x36, 0x7E, 0x6C, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF5
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF6
|
||||
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0xFF, 0xFF, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, # 0xF7
|
||||
{0x00, 0x00, 0x00, 0x02, 0x02, 0x3C, 0x7E, 0x6E, 0x76, 0x76, 0x66, 0x7E, 0xBC, 0x80, 0x00, 0x00}, # 0xF8
|
||||
{0x30, 0x38, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xF9
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFA
|
||||
{0x18, 0x3C, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFB
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFC
|
||||
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0xFD
|
||||
{0x60, 0x60, 0x60, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0xFE
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0xFF
|
||||
]
|
||||
|
||||
@t.Object
|
||||
class _VGAScreenDriver:
|
||||
# 帧缓冲区信息
|
||||
fbv: t.CVoid | t.CPtr # = None
|
||||
fb: t.CUnsignedChar | t.CPtr # = None
|
||||
fw: int # = 800
|
||||
fh: int # = 600
|
||||
fp: int # = 800 * 4 # 3200 800*4
|
||||
ColorFormat: __ColorFormat # = __ColorFormat.ColorFormat_BGRA # 默认使用BGRA格式
|
||||
BgColor: t.CUnsignedInt = 0xFF000080 # RGBA: 不透明深蓝色
|
||||
|
||||
# 初始化VGA驱动
|
||||
def __init__(self, fb: t.CVoid | t.CPtr, width: int, height: int, pitch: int, format: int):
|
||||
# 先做参数合法性检查
|
||||
if fb is None or width <= 0 or height <= 0 or pitch <= 0: return
|
||||
# 更新帧缓冲区参数
|
||||
self.fbv = fb
|
||||
self.fb = t.CUnsignedChar(fb, t.CPtr)
|
||||
self.fw = width
|
||||
self.fh = height
|
||||
self.fp = pitch
|
||||
# 设置颜色格式
|
||||
match format:
|
||||
case 0: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
|
||||
case 1: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
|
||||
case 2: pass
|
||||
case 3: pass
|
||||
case _: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
|
||||
# 检测硬件实际颜色格式(覆盖传入的format)
|
||||
self.DetectColorFormat()
|
||||
# 初始化背景颜色
|
||||
self.ClearScreen(self.BgColor)
|
||||
|
||||
# 检测硬件颜色格式 - 优化测试逻辑,避免误判
|
||||
def DetectColorFormat(self) -> t.CStatic | t.CVoid:
|
||||
if self.fb is None: return
|
||||
fb: t.CUnsignedChar | t.CPtr = t.CUnsignedChar(self.fb, t.CPtr)
|
||||
testX: int = 0
|
||||
testY: int = 0
|
||||
offset: int = testY * self.fp + testX * 4
|
||||
# 保存测试位置原始像素值,避免污染屏幕
|
||||
OriginalPixel: t.CUInt32T = c.Deref(t.CUInt32T(fb + offset, t.CPtr))
|
||||
# 写入测试颜色:青色 (RGBA逻辑值: 0xFF00FFFF)
|
||||
fb[offset + 0] = 0xFF # B
|
||||
fb[offset + 1] = 0xFF # G
|
||||
fb[offset + 2] = 0x00 # R
|
||||
fb[offset + 3] = 0xFF # A
|
||||
# 读取回测试像素
|
||||
b: t.CUnsignedChar = fb[offset + 0]
|
||||
g: t.CUnsignedChar = fb[offset + 1]
|
||||
r: t.CUnsignedChar = fb[offset + 2]
|
||||
# t.CVoid(fb[offset + 3]) # 忽略Alpha
|
||||
# 恢复原始像素
|
||||
c.Set(c.Deref(t.CUInt32T(fb + offset, t.CPtr)), OriginalPixel)
|
||||
# 判定颜色格式
|
||||
if r == 0x00 and g == 0xFF and b == 0xFF: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
|
||||
elif r == 0xFF and g == 0xFF and b == 0x00: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
|
||||
else: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
|
||||
|
||||
# 设置像素颜色 - 统一接口,输入为RGBA逻辑颜色
|
||||
# color格式: 0xAARRGGBB (Alpha, Red, Green, Blue)
|
||||
def SetPixel(self, x: int, y: int, color: t.CUInt32T):
|
||||
fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
if fb is None: return
|
||||
if x < 0 or x >= self.fw or y < 0 or y >= self.fh: return
|
||||
offset: int = y * self.fp + x * 4
|
||||
# 解析RGBA分量
|
||||
r: t.CUnsignedChar = (color >> 16) & 0xFF
|
||||
g: t.CUnsignedChar = (color >> 8) & 0xFF
|
||||
b: t.CUnsignedChar = color & 0xFF
|
||||
a: t.CUnsignedChar = (color >> 24) & 0xFF
|
||||
# 根据硬件格式写入像素
|
||||
match self.ColorFormat:
|
||||
case __ColorFormat.ColorFormat_BGRA:
|
||||
self.fb[offset + 0] = b
|
||||
fb[offset + 1] = g
|
||||
fb[offset + 2] = r
|
||||
fb[offset + 3] = a
|
||||
case __ColorFormat.ColorFormat_RGBA:
|
||||
fb[offset + 0] = r
|
||||
fb[offset + 1] = g
|
||||
fb[offset + 2] = b
|
||||
fb[offset + 3] = a
|
||||
case __ColorFormat.ColorFormat_BGR:
|
||||
fb[offset + 0] = b
|
||||
fb[offset + 1] = g
|
||||
fb[offset + 2] = r
|
||||
case __ColorFormat.ColorFormat_RGB:
|
||||
fb[offset + 0] = r
|
||||
fb[offset + 1] = g
|
||||
fb[offset + 2] = b
|
||||
case _:
|
||||
# 降级到BGRA
|
||||
fb[offset + 0] = b
|
||||
fb[offset + 1] = g
|
||||
fb[offset + 2] = r
|
||||
fb[offset + 3] = a
|
||||
|
||||
# 清除屏幕 - 优化循环效率,减少函数调用开销
|
||||
def ClearScreen(self, color: t.CUInt32T):
|
||||
fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
fp: int = self.fp
|
||||
if fb is None: return
|
||||
PixelSize: int = 3 if self.ColorFormat == __ColorFormat.ColorFormat_BGR or self.ColorFormat == __ColorFormat.ColorFormat_RGB else 4
|
||||
RowSize: int = self.fw * PixelSize
|
||||
# 解析清除颜色的RGBA分量
|
||||
r: t.CUnsignedChar = (color >> 16) & 0xFF
|
||||
g: t.CUnsignedChar = (color >> 8 ) & 0xFF
|
||||
b: t.CUnsignedChar = (color) & 0xFF
|
||||
a: t.CUnsignedChar = (color >> 24) & 0xFF
|
||||
# 逐行填充,比逐像素调用SetPixel快得多
|
||||
for y in range(self.fh):
|
||||
row_ptr: t.CUnsignedChar | t.CPtr = fb + y * fp
|
||||
for x in range(self.fw):
|
||||
offset: int = x * PixelSize
|
||||
match self.ColorFormat:
|
||||
case __ColorFormat.ColorFormat_BGRA:
|
||||
row_ptr[offset + 0] = b
|
||||
row_ptr[offset + 1] = g
|
||||
row_ptr[offset + 2] = r
|
||||
row_ptr[offset + 3] = a
|
||||
case __ColorFormat.ColorFormat_RGBA:
|
||||
row_ptr[offset + 0] = r
|
||||
row_ptr[offset + 1] = g
|
||||
row_ptr[offset + 2] = b
|
||||
row_ptr[offset + 3] = a
|
||||
case __ColorFormat.ColorFormat_BGR:
|
||||
row_ptr[offset + 0] = b
|
||||
row_ptr[offset + 1] = g
|
||||
row_ptr[offset + 2] = r
|
||||
case __ColorFormat.ColorFormat_RGB:
|
||||
row_ptr[offset + 0] = r
|
||||
row_ptr[offset + 1] = g
|
||||
row_ptr[offset + 2] = b
|
||||
|
||||
def Print(self, x: int, y: int, s: str, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, size: int = 16):
|
||||
self.PrintColor(x, y, s, fontcolor, 0x00000000, size)
|
||||
|
||||
def PutcharColor(self, x: int, y: int, cr: t.CChar, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, bgcolor: t.CUnsignedInt = 0x00000000, size: int = 16):
|
||||
fw: int = self.fw
|
||||
fh: int = self.fh
|
||||
fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
if fb is None: return
|
||||
# 提前判断字符整体是否越界(8x16),避免内层循环冗余检查
|
||||
if x < 0 or y < 0 or (x + FONT_WIDTH) > fw or (y + FONT_HEIGHT) > fh: return
|
||||
# 处理字符范围,非ASCII字符替换为默认字符
|
||||
ch: t.CUnsignedChar = t.CUnsignedChar(cr)
|
||||
if ch >= 128: ch = DEFAULT_CHAR
|
||||
# 预解析背景色Alpha,避免内层循环重复计算
|
||||
bg_alpha: t.CUInt8T = (bgcolor >> 24) & 0xFF
|
||||
draw_bg: int = (bg_alpha != 0) # 背景是否需要绘制
|
||||
# 渲染8x16点阵字符
|
||||
for fy in range(FONT_HEIGHT):
|
||||
row: t.CUnsignedChar = font[ch][fy]
|
||||
for fx in range(FONT_WIDTH):
|
||||
px: int = x + fx
|
||||
py: int = y + fy
|
||||
# 检测当前点阵位是否点亮
|
||||
if row & (0x80 >> fx):
|
||||
# 绘制前景色
|
||||
self.SetPixel(px, py, fontcolor)
|
||||
elif draw_bg:
|
||||
# 仅当背景不透明时绘制背景色
|
||||
self.SetPixel(px, py, bgcolor)
|
||||
|
||||
# 在指定位置显示带颜色和字号的字符串
|
||||
def PrintColor(self, x: int, y: int, s: str, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, bgcolor: t.CUnsignedInt = 0x00000000, size: int = 16):
|
||||
fw: int = self.fw
|
||||
fh: int = self.fh
|
||||
# fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
currentX: int = x
|
||||
currentY: int = y
|
||||
if s is None: return
|
||||
# 逐字符处理
|
||||
for _s in s:
|
||||
if _s == '\n':
|
||||
# 换行:重置X,Y增加字符高度
|
||||
currentX = x
|
||||
currentY += size + 2 # 字体大小 + 2像素行间距
|
||||
# 检查换行后是否越界
|
||||
if currentY + size > fh: break
|
||||
else:
|
||||
# 显示普通字符
|
||||
self.PutcharColor(currentX, currentY, _s, fontcolor, bgcolor, size)
|
||||
# 计算字符宽度
|
||||
CharWidth: int = size / 2 + 1 # 简单估算字符宽度
|
||||
currentX += CharWidth
|
||||
# 检查横向是否越界
|
||||
if currentX + CharWidth > fw:
|
||||
# 自动换行
|
||||
currentX = x
|
||||
currentY += size + 2
|
||||
if currentY + size > fh: break
|
||||
Reference in New Issue
Block a user