将本项目升级到基本可用的状态,正在细化各个方面,初次打包了实验版本

This commit is contained in:
TermiNexus committed 2026-07-30 22:33:23 +08:00
1 parent e126548249
commit 36c3357d9f
589 files changed
+2329 -15740

No files matched your search

+149
View File
@@ -0,0 +1,149 @@
.git
.github
.vscode
node_modules
src
tsconfig.json
*.md
*.log
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
*.vsix
junit.xml
.webpack_cache/
# OS files
.DS_Store
Thumbs.db
# Potential venv
.venv
# Agent files
serena/
.beads/
AGENTS.md
# Generated benchmark output
packages/pyright-internal/src/tests/benchmarks/.generated/
# perfCompare.py cached commit bundles
/build/perfCompare/
-251
View File
@@ -1,251 +0,0 @@
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
View File
@@ -1,346 +0,0 @@
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
View File
@@ -1,50 +0,0 @@
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])
-385
View File
@@ -1,385 +0,0 @@
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: list[devfs_directory, MAX_DIRECTORIES] = [0]
directory_count: t.CStatic | t.CInt = 0
files: list[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: list[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
@t.Object
class devfs_directory:
name: list[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: list[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: list[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
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
current: devfs_directory | t.CPtr = self.root_directory
buf: list[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
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
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
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:
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
return 0 if dir_ptr else -1
def create_file(self, path: t.CConst | str,
private_data: t.CVoid | t.CPtr) -> t.CInt:
global file_count
path_copy: list[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
new_file: devfs_file | t.CPtr = c.Addr(files[file_count])
file_count += 1
string.strcpy(new_file.name, file_name)
new_file.private_data = private_data
new_file.parent_dir = dir_ptr
return 0
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
path_copy: list[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
if not file_ptr.open:
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
if file_ptr and file_ptr.close:
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
if file_ptr and file_ptr.read:
return file_ptr.read(fd, buffer, size)
return 0
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
if file_ptr and file_ptr.write:
return file_ptr.write(fd, buffer, size)
return 0
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
if file_ptr and file_ptr.ioctl:
return file_ptr.ioctl(fd, cmd, arg)
return 0
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.__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,
private_data: t.CVoid | t.CPtr) -> t.CInt:
return DevFSObject.create_file(path, 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
serial0_file.ioctl = None
return devfs_create_file("/dev/serial0", serial0_file)
-491
View File
@@ -1,491 +0,0 @@
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
View File
@@ -1,237 +0,0 @@
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
View File
@@ -1,208 +0,0 @@
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)
@@ -1,16 +0,0 @@
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
View File
@@ -1,13 +0,0 @@
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
@@ -1,76 +0,0 @@
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
@@ -1,17 +0,0 @@
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
View File
@@ -1,143 +0,0 @@
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
View File
@@ -1,147 +0,0 @@
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
@@ -1,64 +0,0 @@
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)
File diff suppressed because it is too large. Load diff
-3
View File
@@ -1,3 +0,0 @@
import fat32
@@ -1,146 +0,0 @@
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
View File
@@ -1,134 +0,0 @@
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
View File
@@ -1,46 +0,0 @@
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
View File
@@ -1,116 +0,0 @@
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
View File
@@ -1,161 +0,0 @@
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
View File
@@ -1,37 +0,0 @@
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
View File
@@ -1,111 +0,0 @@
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
View File
@@ -1,77 +0,0 @@
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
View File
@@ -1,93 +0,0 @@
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
View File
@@ -1,415 +0,0 @@
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
View File
@@ -1,330 +0,0 @@
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
View File
@@ -1,85 +0,0 @@
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
View File
@@ -1,152 +0,0 @@
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
View File
@@ -1,305 +0,0 @@
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
View File
@@ -1,504 +0,0 @@
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
-757
View File
@@ -1,757 +0,0 @@
import drivers.serial.uart.serial as serial
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import paging.paging as paging
import sched.process as proc
import sched.sched as sched
import intr.gdt as gdt
# Do NOT import KERN_STACK_SIZE/USER_STACK_SIZE from process - CDefine cross-module import is broken
# Redefine them here to ensure correct values
KERN_STACK_SIZE: t.CDefine = 8192
USER_STACK_SIZE: t.CDefine = 65536
import viperlib
import string
import asm
import t, c
ELFMAG0: t.CDefine = 0x7F
ELFMAG1: t.CDefine = 0x45
ELFMAG2: t.CDefine = 0x4C
ELFMAG3: t.CDefine = 0x46
ELFCLASS64: t.CDefine = 2
ELFDATA2LSB: t.CDefine = 1
ET_EXEC: t.CDefine = 2
ET_DYN: t.CDefine = 3
EM_X86_64: t.CDefine = 62
PT_LOAD: t.CDefine = 1
PT_DYNAMIC: t.CDefine = 2
PF_X: t.CDefine = 1
PF_W: t.CDefine = 2
PF_R: t.CDefine = 4
DT_NULL: t.CDefine = 0
DT_HASH: t.CDefine = 4
DT_STRTAB: t.CDefine = 5
DT_SYMTAB: t.CDefine = 6
DT_STRSZ: t.CDefine = 10
DT_SYMENT: t.CDefine = 11
DT_RELA: t.CDefine = 7
DT_RELASZ: t.CDefine = 8
DT_RELAENT: t.CDefine = 9
DT_PLTRELSZ: t.CDefine = 2
DT_JMPREL: t.CDefine = 23
R_X86_64_64: t.CDefine = 1
R_X86_64_GLOB_DAT: t.CDefine = 6
R_X86_64_JUMP_SLOT: t.CDefine = 7
R_X86_64_RELATIVE: t.CDefine = 8
STB_GLOBAL: t.CDefine = 1
STB_WEAK: t.CDefine = 2
@c.Attribute(t.attr.packed)
class Elf64_Ehdr:
e_ident: t.CArray[t.CUInt8T, 16]
e_type: t.CUInt16T
e_machine: t.CUInt16T
e_version: t.CUInt32T
e_entry: t.CUInt64T
e_phoff: t.CUInt64T
e_shoff: t.CUInt64T
e_flags: t.CUInt32T
e_ehsize: t.CUInt16T
e_phentsize: t.CUInt16T
e_phnum: t.CUInt16T
e_shentsize: t.CUInt16T
e_shnum: t.CUInt16T
e_shstrndx: t.CUInt16T
@c.Attribute(t.attr.packed)
class Elf64_Phdr:
p_type: t.CUInt32T
p_flags: t.CUInt32T
p_offset: t.CUInt64T
p_vaddr: t.CUInt64T
p_paddr: t.CUInt64T
p_filesz: t.CUInt64T
p_memsz: t.CUInt64T
p_align: t.CUInt64T
MAX_PHDRS: t.CDefine = 16
@c.Attribute(t.attr.packed)
class Elf64_Shdr:
sh_name: t.CUInt32T
sh_type: t.CUInt32T
sh_flags: t.CUInt64T
sh_addr: t.CUInt64T
sh_offset: t.CUInt64T
sh_size: t.CUInt64T
sh_link: t.CUInt32T
sh_info: t.CUInt32T
sh_addralign: t.CUInt64T
sh_entsize: t.CUInt64T
@c.Attribute(t.attr.packed)
class Elf64_Sym:
st_name: t.CUInt32T
st_info: t.CUInt8T
st_other: t.CUInt8T
st_shndx: t.CUInt16T
st_value: t.CUInt64T
st_size: t.CUInt64T
@c.Attribute(t.attr.packed)
class Elf64_Rela:
r_offset: t.CUInt64T
r_info: t.CUInt64T
r_addend: t.CInt64T
@c.Attribute(t.attr.packed)
class Elf64_Dyn:
d_tag: t.CInt64T
d_val: t.CUInt64T
MAX_SHDRS: t.CDefine = 64
MAX_DYNS: t.CDefine = 64
MAX_RELAS: t.CDefine = 256
def load_elf(path: t.CConst | str, do_map: t.CInt = 1) -> t.CVoid | t.CPtr:
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp is None:
err: t.CUInt32T = fat32.last_error()
eb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(eb), 64, "[elf] failed to open file err=%d\n", err)
serial.puts(eb)
return None
ehdr_buf: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: t.CUInt32T = fat32.read(fp, c.Addr(ehdr_buf), 64)
if read_len < 64:
serial.puts("[elf] failed to read ehdr\n")
fat32.close(fp)
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[elf] bad magic\n")
fat32.close(fp)
return None
if ehdr.e_ident[4] != ELFCLASS64:
serial.puts("[elf] not ELF64\n")
fat32.close(fp)
return None
if ehdr.e_ident[5] != ELFDATA2LSB:
serial.puts("[elf] not little-endian\n")
fat32.close(fp)
return None
if ehdr.e_type != ET_EXEC and ehdr.e_type != ET_DYN:
serial.puts("[elf] not ET_EXEC or ET_DYN\n")
fat32.close(fp)
return None
if ehdr.e_machine != EM_X86_64:
serial.puts("[elf] not x86_64\n")
fat32.close(fp)
return None
entry_point: t.CUInt64T = ehdr.e_entry
phoff: t.CUInt64T = ehdr.e_phoff
phentsize: t.CUInt16T = ehdr.e_phentsize
phnum: t.CUInt16T = ehdr.e_phnum
if phentsize == 0 or phnum == 0 or phnum > MAX_PHDRS:
serial.puts("[elf] invalid phdr count\n")
fat32.close(fp)
return None
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[elf] entry=0x%lx phoff=%lu phentsize=%u phnum=%u\n", entry_point, phoff, phentsize, phnum)
serial.puts(cr)
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: t.CUInt64T = phoff + t.CUInt64T(pi) * t.CUInt64T(phentsize)
fat32.seek(fp, t.CUInt32T(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
found_load: t.CInt = 0
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
seg_end: t.CUInt64T = phdr_bufs[pi].p_vaddr + phdr_bufs[pi].p_memsz
if found_load == 0:
lowest_vaddr = phdr_bufs[pi].p_vaddr
highest_vaddr_end = seg_end
found_load = 1
else:
if phdr_bufs[pi].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs[pi].p_vaddr
if seg_end > highest_vaddr_end:
highest_vaddr_end = seg_end
if found_load == 0:
serial.puts("[elf] no LOAD segments\n")
fat32.close(fp)
return None
total_memsz: t.CUInt64T = highest_vaddr_end - lowest_vaddr
total_pages: t.CUInt64T = (total_memsz + 0xFFF) // 0x1000
cr2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr2), 80, "[elf] vaddr 0x%lx-0x%lx pages=%lu\n", lowest_vaddr, highest_vaddr_end, total_pages)
serial.puts(cr2)
raw_alloc: t.CVoid | t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
_db_ra: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_db_ra), 80, "[elf] malloc ret raw_alloc=0x%lx\n", t.CUInt64T(raw_alloc))
serial.puts(_db_ra)
if not raw_alloc:
serial.puts("[elf] malloc failed\n")
fat32.close(fp)
return None
phys_base_aligned: t.CUInt64T = (t.CUInt64T(raw_alloc) + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
phys_base: t.CVoid | t.CPtr = t.CVoid(phys_base_aligned, t.CPtr)
string.memset(phys_base, 0, total_pages * 0x1000)
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
vaddr: t.CUInt64T = phdr_bufs[pi].p_vaddr
file_off: t.CUInt64T = phdr_bufs[pi].p_offset
filesz: t.CUInt64T = phdr_bufs[pi].p_filesz
memsz: t.CUInt64T = phdr_bufs[pi].p_memsz
dest_off: t.CUInt64T = vaddr - lowest_vaddr
dest: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(phys_base) + dest_off, t.CPtr)
if filesz > 0:
fat32.seek(fp, t.CUInt32T(file_off))
fat32.read(fp, dest, t.CUInt32T(filesz))
if memsz > filesz:
bss_start: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(dest) + filesz, t.CPtr)
bss_len: t.CUInt64T = memsz - filesz
string.memset(bss_start, 0, bss_len)
fat32.close(fp)
virt_page_start: t.CUInt64T = lowest_vaddr & ~t.CUInt64T(0xFFF)
phys_page_start: t.CUInt64T = t.CUInt64T(phys_base) & ~t.CUInt64T(0xFFF)
map_end: t.CUInt64T = (highest_vaddr_end + 0xFFF) & ~t.CUInt64T(0xFFF)
num_map_pages: t.CUInt64T = (map_end - virt_page_start) // 0x1000
# Store mapping info for spawn_elf (used when do_map=0)
global _last_elf_phys_page_start, _last_elf_virt_page_start, _last_elf_num_map_pages
_last_elf_phys_page_start = phys_page_start
_last_elf_virt_page_start = virt_page_start
_last_elf_num_map_pages = num_map_pages
if do_map != 0:
for mi in range(num_map_pages):
virt_addr: t.CUInt64T = virt_page_start + mi * 0x1000
phys_addr: t.CUInt64T = phys_page_start + mi * 0x1000
page_flags: t.CUInt64T = paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER
paging.MapPage(virt_addr, phys_addr, page_flags)
entry_addr: t.CVoid | t.CPtr = t.CVoid(entry_point, t.CPtr)
return entry_addr
def run_elf(path: t.CConst | str) -> t.CInt:
entry: t.CVoid | t.CPtr = load_elf(path)
if entry is None:
serial.puts("[elf] load failed\n")
return -1
serial.puts("[elf] jumping to entry...\n")
c.Asm(f"""call {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
serial.puts("[elf] returned from entry\n")
return 0
MAX_SPAWNED: t.CDefine = 8
_elf_entries: t.CArray[t.CVoid | t.CPtr, MAX_SPAWNED]
# User stack virtual address: top of 48-bit user space, 64KB below
USER_STACK_VTOP: t.CDefine = 0x7FFFFFE00000
# Globals for ELF mapping info (set by load_elf when do_map=0, used by spawn_elf
# to map ELF pages in the cloned PML4 instead of kernel PML4).
# ROOT CAUSE: previously load_elf mapped ELF vaddr (e.g. 0x400000) into the
# kernel PML4, overwriting the identity mapping of buddy system memory_block
# headers at 0x400000. This corrupted buddy metadata -> malloc failures,
# pid=0, and #GP in split_block. Fix: load_elf does NOT map; spawn_elf maps
# in the cloned PML4 after clone_for_process.
_last_elf_phys_page_start: t.CUInt64T = 0
_last_elf_virt_page_start: t.CUInt64T = 0
_last_elf_num_map_pages: t.CUInt64T = 0
def _elf_entry_wrapper(arg: t.CVoid | t.CPtr) -> t.CInt:
pid: t.CInt = t.CInt(t.CUInt64T(arg))
_db1: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_db1), 64, "[elf] wrapper pid=%d\n", pid)
serial.puts(_db1)
# Disable interrupts around switch_pid + MapPage + TSS setup: @pml4 is a global
# that switch_pid modifies. A timer interrupt mid-section would make the scheduler
# call switch_pid for another thread, corrupting @pml4 for our MapPage calls.
asm.cli()
proc.switch_pid(pid)
cur_p: proc.Process | t.CPtr = proc.ProcessManager.current()
entry_fn: t.CVoid | t.CPtr = cur_p.entry
if entry_fn is not None:
user_stack_vtop: t.CUInt64T = USER_STACK_VTOP
us_sz: t.CUInt64T = USER_STACK_SIZE
user_stack_vbottom: t.CUInt64T = USER_STACK_VTOP - us_sz
# Physical pages of the user stack (allocated by mm.malloc, identity-mapped)
us_size: t.CUInt64T = USER_STACK_SIZE
phys_bottom: t.CUInt64T = (cur_p.user_stack - us_size) & ~t.CUInt64T(0xFFF)
# Map each page of the user stack at the virtual address with PTE_USER
num_stack_pages: t.CUInt64T = 16 # USER_STACK_SIZE(65536) / PAGE_SIZE(4096) = 16
si: t.CUInt64T
for si in range(num_stack_pages):
vaddr: t.CUInt64T = (user_stack_vbottom & ~t.CUInt64T(0xFFF)) + si * t.CUInt64T(0x1000)
paddr: t.CUInt64T = phys_bottom + si * t.CUInt64T(0x1000)
paging.MapPage(vaddr, paddr, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
# Set TSS RSP0 so interrupts from Ring 3 use kernel stack
gdt.set_tss_rsp0(cur_p.kern_stack)
# Set GS kernel_rsp0 for syscall entry from Ring 3
cpu.set_kernel_rsp0(cur_p.kern_stack)
# Keep interrupts disabled until iretq: drop_to_user_mode's iretq
# will set RFLAGS.IF from the saved frame (0x202) for user mode.
# This prevents timer interrupt preemption between TSS setup and iretq.
# Drop to Ring 3 user mode via iretq
proc.drop_to_user_mode(entry_fn, user_stack_vtop, cur_p.kern_stack)
cur: proc.Process | t.CPtr = proc.ProcessManager.current()
cur.exit()
return 0
def spawn_elf(path: t.CConst | str) -> t.CInt:
fat32.lock()
name_start: t.CInt = 0
si: t.CInt = 0
while True:
ch: t.CChar = path[si]
if ch == 0: break
if ch == 47:
name_start = si + 1
si += 1
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
fp_scan: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp_scan is None:
serr: t.CUInt32T = fat32.last_error()
seb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(seb), 64, "[elf] spawn scan open failed err=%d\n", serr)
serial.puts(seb)
fat32.unlock()
return -1
if fp_scan is not None:
ehdr_buf_s: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf_s), 0, 64)
fat32.read(fp_scan, c.Addr(ehdr_buf_s), 64)
ehdr_s: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf_s)
if ehdr_s.e_type == ET_EXEC or ehdr_s.e_type == ET_DYN:
phoff_s: t.CUInt64T = ehdr_s.e_phoff
phentsize_s: t.CUInt16T = ehdr_s.e_phentsize
phnum_s: t.CUInt16T = ehdr_s.e_phnum
if phentsize_s > 0 and phnum_s > 0 and phnum_s <= MAX_PHDRS:
phdr_bufs_s: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs_s), 0, MAX_PHDRS * 56)
found_load_s: t.CInt = 0
for pi_s in range(phnum_s):
fat32.seek(fp_scan, t.CUInt32T(phoff_s + t.CUInt64T(pi_s) * t.CUInt64T(phentsize_s)))
fat32.read(fp_scan, c.Addr(phdr_bufs_s[pi_s]), 56)
if phdr_bufs_s[pi_s].p_type == PT_LOAD:
seg_end_s: t.CUInt64T = phdr_bufs_s[pi_s].p_vaddr + phdr_bufs_s[pi_s].p_memsz
if found_load_s == 0:
lowest_vaddr = phdr_bufs_s[pi_s].p_vaddr
highest_vaddr_end = seg_end_s
found_load_s = 1
else:
if phdr_bufs_s[pi_s].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs_s[pi_s].p_vaddr
if seg_end_s > highest_vaddr_end:
highest_vaddr_end = seg_end_s
fat32.close(fp_scan)
isolate_va: t.CUInt64T = lowest_vaddr
if isolate_va == 0:
isolate_va = 0x400000
# Load ELF to physical memory WITHOUT mapping in kernel PML4.
# do_map=0: load_elf stores mapping info in globals for spawn_elf to use.
# ROOT CAUSE FIX: previously load_elf mapped ELF vaddr (e.g. 0x400000) into
# kernel PML4, overwriting identity mapping of buddy memory_block headers.
entry: t.CVoid | t.CPtr = load_elf(path, 0)
if entry is None:
serial.puts("[elf] spawn: load failed\n")
fat32.unlock()
return -1
# Clone kernel PML4 (identity mapping intact, no ELF mapping yet)
proc_pml4: t.CUInt64T = paging.clone_for_process(isolate_va)
slog1: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog1), 80, "[elf] spawn: clone pml4=0x%lx va=0x%lx\n", proc_pml4, isolate_va)
serial.puts(slog1)
if proc_pml4 == 0:
serial.puts("[elf] spawn: clone_for_process failed\n")
fat32.unlock()
return -1
# Map ELF pages in the CLONED PML4 (not kernel's).
# This prevents overwriting kernel identity mapping at 0x400000 which
# would corrupt buddy system memory_block headers.
# Must disable interrupts: @pml4 global is used by MapPage and a timer
# interrupt mid-section would call switch_pid, corrupting @pml4.
asm.cli()
_kernel_cr3: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(_kernel_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3""", op=[t.ASM_DESCR.CLOBBER_MEMORY])
c.Asm(f"mov cr3, {c.AsmInp(proc_pml4, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(proc_pml4)
mi: t.CUInt64T
for mi in range(_last_elf_num_map_pages):
_va: t.CUInt64T = _last_elf_virt_page_start + mi * 0x1000
_pa: t.CUInt64T = _last_elf_phys_page_start + mi * 0x1000
paging.MapPage(_va, _pa, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
c.Asm(f"mov cr3, {c.AsmInp(_kernel_cr3, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(_kernel_cr3)
asm.sti()
p: proc.Process | t.CPtr = proc.ProcessManager.create_process(path[name_start:], entry)
if p is None:
serial.puts("[elf] spawn: create_process failed\n")
fat32.unlock()
return -2
p.elf_base = t.CUInt64T(entry)
p.pml4_root = proc_pml4
if p.pid >= 0 and p.pid < MAX_SPAWNED:
_elf_entries[p.pid] = entry
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(_elf_entry_wrapper, t.CVoid(t.CUInt64T(p.pid), t.CPtr), p.pid)
if th is None:
serial.puts("[elf] spawn: create_thread failed\n")
p.exit()
fat32.unlock()
return -3
tid: t.CInt = th.tid
p.addThread(tid)
slog: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog), 80, "[elf] spawn: pid=%d tid=%d entry=0x%lx pml4=0x%lx\n", p.pid, tid, t.CUInt64T(entry), p.pml4_root)
serial.puts(slog)
fat32.unlock()
return p.pid
def _resolve_symbol(name: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CPtr:
nm: t.CInt = 0
while c.Deref(name + nm) != 0:
nm += 1
cmp_name: t.CConst | t.CChar | t.CPtr = name
cmp_len: t.CInt = nm
if nm > 9:
sha1_len2: t.CInt = 0
for si2 in range(nm):
ch2: t.CChar = c.Deref(name + si2)
if ch2 == 46:
if sha1_len2 >= 8:
cmp_name = t.CConst(t.CUInt64T(name) + si2 + 1, t.CPtr)
cmp_len = nm - si2 - 1
break
if ch2 == 0:
break
if (ch2 >= 48 and ch2 <= 57) or (ch2 >= 97 and ch2 <= 102):
sha1_len2 += 1
else:
break
if cmp_len == 11:
match: t.CInt = 1
for i in range(cmp_len):
if c.Deref(cmp_name + i) != c.Deref("serial_puts" + i):
match = 0
if match:
return t.CVoid(c.Addr(serial.puts), t.CPtr)
return None
_so_strtab: t.CVoid | t.CPtr
_so_symtab: t.CVoid | t.CPtr
_so_syment: t.CUInt64T
_so_sym_count: t.CInt
def load_so(path: t.CConst | str) -> t.CVoid | t.CPtr:
fat32.lock()
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp is None:
serial.puts("[so] failed to open file\n")
fat32.unlock()
return None
ehdr_buf: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: t.CUInt32T = fat32.read(fp, c.Addr(ehdr_buf), 64)
if read_len < 64:
serial.puts("[so] failed to read ehdr\n")
fat32.close(fp)
fat32.unlock()
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[so] bad magic\n")
fat32.close(fp)
fat32.unlock()
return None
if ehdr.e_ident[4] != ELFCLASS64:
serial.puts("[so] not ELF64\n")
fat32.close(fp)
fat32.unlock()
return None
if ehdr.e_type == ET_DYN:
pass
elif ehdr.e_type == ET_EXEC:
pass
else:
serial.puts("[so] not ET_DYN or ET_EXEC\n")
fat32.close(fp)
fat32.unlock()
return None
phoff: t.CUInt64T = ehdr.e_phoff
phentsize: t.CUInt16T = ehdr.e_phentsize
phnum: t.CUInt16T = ehdr.e_phnum
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: t.CUInt64T = phoff + t.CUInt64T(pi) * t.CUInt64T(phentsize)
fat32.seek(fp, t.CUInt32T(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
found_load: t.CInt = 0
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
seg_end: t.CUInt64T = phdr_bufs[pi].p_vaddr + phdr_bufs[pi].p_memsz
if found_load == 0:
lowest_vaddr = phdr_bufs[pi].p_vaddr
highest_vaddr_end = seg_end
found_load = 1
else:
if phdr_bufs[pi].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs[pi].p_vaddr
if seg_end > highest_vaddr_end:
highest_vaddr_end = seg_end
if found_load == 0:
serial.puts("[so] no LOAD segments\n")
fat32.close(fp)
fat32.unlock()
return None
total_memsz: t.CUInt64T = highest_vaddr_end - lowest_vaddr
total_pages: t.CUInt64T = (total_memsz + 0xFFF) // 0x1000
so_load_addr: t.CUInt64T = 0x600000
raw_alloc: t.CVoid | t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
if not raw_alloc:
serial.puts("[so] malloc failed\n")
fat32.close(fp)
fat32.unlock()
return None
phys_base_aligned: t.CUInt64T = (t.CUInt64T(raw_alloc) + 0xFFF) & ~t.CUInt64T(0xFFF)
phys_base: t.CVoid | t.CPtr = t.CVoid(phys_base_aligned, t.CPtr)
string.memset(phys_base, 0, total_pages * 0x1000)
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
vaddr: t.CUInt64T = phdr_bufs[pi].p_vaddr
file_off: t.CUInt64T = phdr_bufs[pi].p_offset
filesz: t.CUInt64T = phdr_bufs[pi].p_filesz
memsz: t.CUInt64T = phdr_bufs[pi].p_memsz
dest_off: t.CUInt64T = vaddr - lowest_vaddr
dest: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(phys_base) + dest_off, t.CPtr)
if filesz > 0:
fat32.seek(fp, t.CUInt32T(file_off))
fat32.read(fp, dest, t.CUInt32T(filesz))
if memsz > filesz:
bss_start: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(dest) + filesz, t.CPtr)
bss_len: t.CUInt64T = memsz - filesz
string.memset(bss_start, 0, bss_len)
virt_page_start: t.CUInt64T = (so_load_addr + lowest_vaddr) & ~t.CUInt64T(0xFFF)
phys_page_start: t.CUInt64T = t.CUInt64T(phys_base) & ~t.CUInt64T(0xFFF)
map_end: t.CUInt64T = (so_load_addr + highest_vaddr_end + 0xFFF) & ~t.CUInt64T(0xFFF)
num_map_pages: t.CUInt64T = (map_end - virt_page_start) // 0x1000
for mi in range(num_map_pages):
virt_addr: t.CUInt64T = virt_page_start + mi * 0x1000
phys_addr: t.CUInt64T = phys_page_start + mi * 0x1000
paging.MapPage(virt_addr, phys_addr, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
base_vaddr: t.CUInt64T = so_load_addr + lowest_vaddr
dyn_buf: t.CArray[Elf64_Dyn, MAX_DYNS]
string.memset(c.Addr(dyn_buf), 0, MAX_DYNS * 16)
dyn_count: t.CInt = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_DYNAMIC:
fat32.seek(fp, t.CUInt32T(phdr_bufs[pi].p_offset))
dyn_read: t.CUInt32T = fat32.read(fp, c.Addr(dyn_buf), t.CUInt32T(phdr_bufs[pi].p_filesz))
dyn_count = t.CInt(dyn_read) // 16
strtab_vaddr: t.CUInt64T = 0
symtab_vaddr: t.CUInt64T = 0
hash_vaddr: t.CUInt64T = 0
syment: t.CUInt64T = 0
rela_vaddr: t.CUInt64T = 0
relasz: t.CUInt64T = 0
jmprel_vaddr: t.CUInt64T = 0
pltrelsz: t.CUInt64T = 0
for di in range(dyn_count):
if dyn_buf[di].d_tag == DT_NULL: break
if dyn_buf[di].d_tag == DT_STRTAB: strtab_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_SYMTAB: symtab_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_HASH: hash_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_SYMENT: syment = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_RELA: rela_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_RELASZ: relasz = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_JMPREL: jmprel_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_PLTRELSZ: pltrelsz = dyn_buf[di].d_val
strtab_ptr: t.CVoid | t.CPtr = t.CVoid(strtab_vaddr + so_load_addr, t.CPtr)
symtab_ptr: t.CVoid | t.CPtr = t.CVoid(symtab_vaddr + so_load_addr, t.CPtr)
if rela_vaddr != 0 and relasz > 0:
rela_count: t.CUInt64T = relasz // 24
for ri in range(rela_count):
rela: Elf64_Rela | t.CPtr = t.CVoid(t.CUInt64T(rela_vaddr) + so_load_addr + ri * 24, t.CPtr)
r_type: t.CUInt32T = t.CUInt32T(rela.r_info & 0xFFFFFFFF)
r_sym: t.CUInt32T = t.CUInt32T(rela.r_info >> 32)
target_addr: t.CVoid | t.CPtr = t.CVoid(rela.r_offset + so_load_addr, t.CPtr)
if r_type == R_X86_64_RELATIVE:
val: t.CUInt64T = t.CUInt64T(rela.r_addend) + so_load_addr
string.memcpy(target_addr, c.Addr(val), 8)
elif r_type == R_X86_64_64 or r_type == R_X86_64_GLOB_DAT or r_type == R_X86_64_JUMP_SLOT:
sym: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(symtab_ptr) + t.CUInt64T(r_sym) * syment, t.CPtr)
sym_name: t.CConst | t.CChar | t.CPtr = t.CConst(t.CUInt64T(strtab_ptr) + sym.st_name, t.CPtr)
resolved: t.CVoid | t.CPtr = _resolve_symbol(sym_name)
if resolved is not None:
val2: t.CUInt64T = t.CUInt64T(resolved) + t.CUInt64T(rela.r_addend)
string.memcpy(target_addr, c.Addr(val2), 8)
elif sym.st_value != 0:
val3: t.CUInt64T = sym.st_value + so_load_addr + t.CUInt64T(rela.r_addend)
string.memcpy(target_addr, c.Addr(val3), 8)
if jmprel_vaddr != 0 and pltrelsz > 0:
jmprel_count: t.CUInt64T = pltrelsz // 24
for ji in range(jmprel_count):
rela2: Elf64_Rela | t.CPtr = t.CVoid(jmprel_vaddr + so_load_addr + ji * 24, t.CPtr)
r_type2: t.CUInt32T = t.CUInt32T(rela2.r_info & 0xFFFFFFFF)
r_sym2: t.CUInt32T = t.CUInt32T(rela2.r_info >> 32)
target2: t.CVoid | t.CPtr = t.CVoid(rela2.r_offset + so_load_addr, t.CPtr)
if r_type2 == R_X86_64_JUMP_SLOT or r_type2 == R_X86_64_GLOB_DAT:
sym2: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(symtab_ptr) + t.CUInt64T(r_sym2) * syment, t.CPtr)
sym_name2: t.CConst | t.CChar | t.CPtr = t.CConst(t.CUInt64T(strtab_ptr) + sym2.st_name, t.CPtr)
resolved2: t.CVoid | t.CPtr = _resolve_symbol(sym_name2)
if resolved2 is not None:
val4: t.CUInt64T = t.CUInt64T(resolved2) + t.CUInt64T(rela2.r_addend)
string.memcpy(target2, c.Addr(val4), 8)
elif sym2.st_value != 0:
val5: t.CUInt64T = sym2.st_value + so_load_addr + t.CUInt64T(rela2.r_addend)
string.memcpy(target2, c.Addr(val5), 8)
else:
cr3: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr3), 80, "[so] WARN: unresolved PLT sym offset=%lu\n", sym2.st_name)
serial.puts(cr3)
fat32.close(fp)
_so_strtab = strtab_ptr
_so_symtab = symtab_ptr
_so_syment = syment
_so_sym_count = 0
if hash_vaddr != 0:
hash_ptr: t.CVoid | t.CPtr = t.CVoid(hash_vaddr + so_load_addr, t.CPtr)
nchain: t.CUInt32T = c.Deref(t.CVoid(t.CUInt64T(hash_ptr) + 4, t.CPtr))
_so_sym_count = t.CInt(nchain)
elif syment > 0 and strtab_vaddr > symtab_vaddr and symtab_vaddr != 0:
sym_tab_size: t.CUInt64T = strtab_vaddr - symtab_vaddr
_so_sym_count = t.CInt(sym_tab_size // syment)
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[so] loaded at 0x%lx\n", base_vaddr)
serial.puts(cr)
fat32.unlock()
return t.CVoid(base_vaddr, t.CPtr)
def get_so_symbol(so_base: t.CVoid | t.CPtr, name: t.CConst | t.CChar | t.CPtr, so_path: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CPtr:
if _so_symtab is None or _so_strtab is None or _so_syment == 0:
return None
if name is None:
return None
for symi in range(_so_sym_count):
sb2: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(_so_symtab) + t.CUInt64T(symi) * _so_syment, t.CPtr)
if sb2.st_value != 0 and sb2.st_shndx != 0:
sym_name_off2: t.CUInt32T = sb2.st_name
cmp_off2: t.CUInt32T = sym_name_off2
match2: t.CInt = 0
ni2: t.CInt = 0
while True:
sc3: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + cmp_off2 + ni2, t.CPtr))
nc3: t.CChar = c.Deref(name + ni2)
if sc3 != nc3:
break
if sc3 == 0:
match2 = 1
break
ni2 += 1
if match2 == 0:
dot_pos3: t.CUInt32T = sym_name_off2
is_sha1_2: t.CInt = 0
sha1_len_2: t.CUInt32T = 0
while True:
dc4: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + dot_pos3, t.CPtr))
if dc4 == 46:
if sha1_len_2 >= 8:
is_sha1_2 = 1
break
if dc4 == 0:
break
if (dc4 >= 48 and dc4 <= 57) or (dc4 >= 97 and dc4 <= 102):
sha1_len_2 += 1
else:
break
dot_pos3 += 1
if is_sha1_2:
cmp_off2 = dot_pos3 + 1
match2 = 1
ni2 = 0
while True:
sc4: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + cmp_off2 + ni2, t.CPtr))
nc4: t.CChar = c.Deref(name + ni2)
if sc4 != nc4:
match2 = 0
break
if sc4 == 0:
break
ni2 += 1
if match2:
result_addr: t.CUInt64T = t.CUInt64T(so_base) + sb2.st_value
dbg2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(dbg2), 80, "[so] found '%s' at 0x%lx\n", t.CVoid(t.CUInt64T(_so_strtab) + sym_name_off2, t.CPtr), result_addr)
serial.puts(dbg2)
return t.CVoid(result_addr, t.CPtr)
serial.puts("[so] symbol not found\n")
return None
-2
View File
@@ -1,2 +0,0 @@
from . import gdt
from . import idt
-142
View File
@@ -1,142 +0,0 @@
import t, c
@c.Attribute(t.attr.packed)
class gdt_entry:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
@c.Attribute(t.attr.packed)
class gdt_entry64:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
base_upper: t.CUInt32T
reserved: t.CUInt32T
@c.Attribute(t.attr.packed)
class gdt_ptr:
limit: t.CUInt16T
base: t.CUInt64T
gdt: t.CArray[gdt_entry, 7] = []
gp: t.CArray[t.CUInt8T, 10]
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
tss_buf: t.CArray[t.CUInt8T, 104]
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
USER_CODE_SEG: t.CDefine | t.CUInt16T = 0x18
USER_DATA_SEG: t.CDefine | t.CUInt16T = 0x20
TSS_SEG: t.CDefine | t.CUInt16T = 0x28
def init():
global gp, gdt, tss_buf
gdt[0].limit_low = 0
gdt[0].base_low = 0
gdt[0].base_middle = 0
gdt[0].access = 0
gdt[0].granularity = 0
gdt[0].base_high = 0
gdt[1].limit_low = 0
gdt[1].base_low = 0
gdt[1].base_middle = 0
gdt[1].access = 0x9A
gdt[1].granularity = 0x20
gdt[1].base_high = 0
gdt[2].limit_low = 0
gdt[2].base_low = 0
gdt[2].base_middle = 0
gdt[2].access = 0x92
gdt[2].granularity = 0xCF
gdt[2].base_high = 0
gdt[3].limit_low = 0
gdt[3].base_low = 0
gdt[3].base_middle = 0
gdt[3].access = 0xFA
gdt[3].granularity = 0x20
gdt[3].base_high = 0
gdt[4].limit_low = 0
gdt[4].base_low = 0
gdt[4].base_middle = 0
gdt[4].access = 0xF2
gdt[4].granularity = 0xCF
gdt[4].base_high = 0
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
setTSS64(5, t.CUInt64T(c.Addr(tss_buf)), 103)
c.Asm("""lea rax, [rip + gdt]
lea rcx, [rip + gp]
mov word ptr [rcx], 0x37
mov qword ptr [rcx+2], rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
flush()
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
tss_buf[102] = 0x68
tss_buf[103] = 0x00
# Load Task Register with TSS selector 0x28
c.Asm("""mov ax, 0x28
ltr ax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@c.Attribute(t.attr.naked)
def flush():
c.Asm("""lea rax, [rip + gp]
lgdt [rax]
push 0x08
lea rax, [rip+2f]
push rax
.byte 0x48, 0xcb
2:
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
def set_tss_rsp0(rsp0: t.CUInt64T):
global tss_buf
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
tss_buf[4] = t.CUInt8T(rsp0 & 0xFF)
tss_buf[5] = t.CUInt8T((rsp0 >> 8) & 0xFF)
tss_buf[6] = t.CUInt8T((rsp0 >> 16) & 0xFF)
tss_buf[7] = t.CUInt8T((rsp0 >> 24) & 0xFF)
tss_buf[8] = t.CUInt8T((rsp0 >> 32) & 0xFF)
tss_buf[9] = t.CUInt8T((rsp0 >> 40) & 0xFF)
tss_buf[10] = t.CUInt8T((rsp0 >> 48) & 0xFF)
tss_buf[11] = t.CUInt8T((rsp0 >> 56) & 0xFF)
def setGate(num: int, base: t.CUInt64T, limit: t.CUInt32T, access: t.CUInt8T, gran: t.CUInt8T):
global gdt
gdt[num].limit_low = (limit & 0xFFFF)
gdt[num].base_low = (base & 0xFFFF)
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
gdt[num].access = access
def setTSS64(num: int, base: t.CUInt64T, limit: t.CUInt32T):
global gdt
gdt[num].limit_low = limit & 0xFFFF
gdt[num].base_low = base & 0xFFFF
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].access = 0x89
gdt[num].granularity = 0x00
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
gdt[num + 1].base_middle = 0
gdt[num + 1].access = 0
gdt[num + 1].granularity = 0
gdt[num + 1].base_high = 0
-415
View File
@@ -1,415 +0,0 @@
import platform.pch.pic as pic
import platform.pch.timer as timer
import sched.sched as sched
import drivers.serial.uart.serial as serial
import viperlib
import asm
import t, c
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
@c.Attribute(t.attr.packed)
class idt_entry:
base_low: t.CUInt16T
selector: t.CUInt16T
ist_attr: t.CUInt8T
type_attr: t.CUInt8T
base_middle: t.CUInt16T
base_high: t.CUInt32T
reserved1: t.CUInt32T
idt: t.CArray[idt_entry, 256] = []
irq_handler_t: t.CTypedef = t.Callable[[], t.CInt]
def isr0() -> t.State: pass
def isr1() -> t.State: pass
def isr2() -> t.State: pass
def isr3() -> t.State: pass
def isr4() -> t.State: pass
def isr5() -> t.State: pass
def isr6() -> t.State: pass
def isr7() -> t.State: pass
def isr8() -> t.State: pass
def isr9() -> t.State: pass
def isr10() -> t.State: pass
def isr11() -> t.State: pass
def isr12() -> t.State: pass
def isr13() -> t.State: pass
def isr14() -> t.State: pass
def isr15() -> t.State: pass
def isr16() -> t.State: pass
def isr17() -> t.State: pass
def isr18() -> t.State: pass
def isr19() -> t.State: pass
def isr20() -> t.State: pass
def isr21() -> t.State: pass
def isr22() -> t.State: pass
def isr23() -> t.State: pass
def isr24() -> t.State: pass
def isr25() -> t.State: pass
def isr26() -> t.State: pass
def isr27() -> t.State: pass
def isr28() -> t.State: pass
def isr29() -> t.State: pass
def isr30() -> t.State: pass
def isr31() -> t.State: pass
def isr32() -> t.State: pass
def isr33() -> t.State: pass
def isr34() -> t.State: pass
def isr35() -> t.State: pass
def isr36() -> t.State: pass
def isr37() -> t.State: pass
def isr38() -> t.State: pass
def isr39() -> t.State: pass
def isr40() -> t.State: pass
def isr41() -> t.State: pass
def isr42() -> t.State: pass
def isr43() -> t.State: pass
def isr44() -> t.State: pass
def isr45() -> t.State: pass
def isr46() -> t.State: pass
def isr47() -> t.State: pass
def isr80() -> t.State: pass
def isr_default() -> t.State: pass
def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
global idt
idt[num].base_low = (base & 0xFFFF)
idt[num].base_middle = (base >> 16) & 0xFFFF
idt[num].base_high = (base >> 32) & 0xFFFFFFFF
idt[num].selector = sel
idt[num].ist_attr = 0
idt[num].type_attr = flags
idt[num].reserved1 = 0
def isrCommonhandler(interrupt: t.CInt):
c.Asm(f"""mov dx, 0x3F8
mov al, 91
out dx, al
mov ecx, {c.AsmInp(interrupt, t.ASM_DESCR.REG_ANY)}
mov rax, rcx
shr rax, 4
and al, 15
add al, 48
cmp al, 57
jle 1f
add al, 7
1:
out dx, al
mov rax, rcx
and al, 15
add al, 48
cmp al, 57
jle 2f
add al, 7
2:
out dx, al
mov al, 93
out dx, al""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
# Print CR2 for page faults (ISR 14)
if interrupt == 14:
cr2: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(cr2, t.ASM_DESCR.OUTPUT_REG)}, cr2""",
op=[t.ASM_DESCR.CLOBBER_RAX])
fault_rip: t.CUInt64T = 0
fault_err: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(fault_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(fault_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(buf), 80, "[PF] cr2=0x%lx rip=0x%lx err=0x%lx\n", cr2, fault_rip, fault_err)
serial.puts(buf)
elif interrupt == 13:
gp_rip: t.CUInt64T = 0
gp_err: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(gp_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(gp_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
gp_buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(gp_buf), 80, "[GP] rip=0x%lx err=0x%lx\n", gp_rip, gp_err)
serial.puts(gp_buf)
s: sched.Scheduler | t.CPtr = sched._sched_ptr
# 如果调度器未初始化,直接进入安全停机状态
if s == 0:
serial.puts(" KERNEL PANIC (sched not init)\n")
while True:
asm.sti()
asm.hlt()
tid: t.CInt = s.current_tid
if tid == 0:
serial.puts(" KERNEL PANIC\n")
while True:
asm.sti()
asm.hlt()
buf2: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf2), 64, " exc in tid=%d, terminating\n", tid)
serial.puts(buf2)
s.threads[tid].state = 3
# Restore GS to kernel-normal state before _yield().
# ISR entry does swapgs for user-mode exceptions (GS_BASE=&_per_cpu).
# Since _yield() switches to another thread and never returns via ISR exit,
# the swapgs at ISR exit is never executed. We must swap back here.
# Check IA32_GS_BASE (MSR 0xC0000101): if non-zero, swapgs was done at entry.
c.Asm(f"""mov ecx, 0xC0000101
rdmsr
shl rdx, 32
or rax, rdx
test rax, rax
jz 1f
swapgs
1:""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
sched.Scheduler._yield()
while True:
asm.sti()
asm.hlt()
def isr0_handler() -> t.CExport | t.CVoid: isrCommonhandler(0)
def isr1_handler() -> t.CExport | t.CVoid: isrCommonhandler(1)
def isr2_handler() -> t.CExport | t.CVoid: isrCommonhandler(2)
def isr3_handler() -> t.CExport | t.CVoid: isrCommonhandler(3)
def isr4_handler() -> t.CExport | t.CVoid: isrCommonhandler(4)
def isr5_handler() -> t.CExport | t.CVoid: isrCommonhandler(5)
def isr6_handler() -> t.CExport | t.CVoid: isrCommonhandler(6)
def isr7_handler() -> t.CExport | t.CVoid: isrCommonhandler(7)
def isr8_handler() -> t.CExport | t.CVoid: isrCommonhandler(8)
def isr9_handler() -> t.CExport | t.CVoid: isrCommonhandler(9)
def isr10_handler() -> t.CExport | t.CVoid: isrCommonhandler(10)
def isr11_handler() -> t.CExport | t.CVoid: isrCommonhandler(11)
def isr12_handler() -> t.CExport | t.CVoid: isrCommonhandler(12)
def isr13_handler() -> t.CExport | t.CVoid:
isrCommonhandler(13)
def isr14_handler() -> t.CExport | t.CVoid: isrCommonhandler(14)
def isr15_handler() -> t.CExport | t.CVoid: isrCommonhandler(15)
def isr16_handler() -> t.CExport | t.CVoid: isrCommonhandler(16)
def isr17_handler() -> t.CExport | t.CVoid: isrCommonhandler(17)
def isr18_handler() -> t.CExport | t.CVoid: isrCommonhandler(18)
def isr19_handler() -> t.CExport | t.CVoid: isrCommonhandler(19)
def isr20_handler() -> t.CExport | t.CVoid: isrCommonhandler(20)
def isr21_handler() -> t.CExport | t.CVoid: isrCommonhandler(21)
def isr22_handler() -> t.CExport | t.CVoid: isrCommonhandler(22)
def isr23_handler() -> t.CExport | t.CVoid: isrCommonhandler(23)
def isr24_handler() -> t.CExport | t.CVoid: isrCommonhandler(24)
def isr25_handler() -> t.CExport | t.CVoid: isrCommonhandler(25)
def isr26_handler() -> t.CExport | t.CVoid: isrCommonhandler(26)
def isr27_handler() -> t.CExport | t.CVoid: isrCommonhandler(27)
def isr28_handler() -> t.CExport | t.CVoid: isrCommonhandler(28)
def isr29_handler() -> t.CExport | t.CVoid: isrCommonhandler(29)
def isr30_handler() -> t.CExport | t.CVoid: isrCommonhandler(30)
def isr31_handler() -> t.CExport | t.CVoid: isrCommonhandler(31)
def isr32_handler() -> t.CExport | t.CVoid:
timer.timer_handler()
def isr33_handler() -> t.CExport | t.CVoid:
handler: irq_handler_t = irqGetHandler(1)
if handler:
c.Asm(f"""call {c.AsmInp(handler, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(1)
def isr34_handler() -> t.CExport | t.CVoid:
handler2: irq_handler_t = irqGetHandler(2)
if handler2:
c.Asm(f"""call {c.AsmInp(handler2, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(2)
def isr35_handler() -> t.CExport | t.CVoid:
handler3: irq_handler_t = irqGetHandler(3)
if handler3:
c.Asm(f"""call {c.AsmInp(handler3, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(3)
def isr36_handler() -> t.CExport | t.CVoid:
handler4: irq_handler_t = irqGetHandler(4)
if handler4:
c.Asm(f"""call {c.AsmInp(handler4, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(4)
def isr37_handler() -> t.CExport | t.CVoid:
handler5: irq_handler_t = irqGetHandler(5)
if handler5:
c.Asm(f"""call {c.AsmInp(handler5, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(5)
def isr38_handler() -> t.CExport | t.CVoid:
handler6: irq_handler_t = irqGetHandler(6)
if handler6:
c.Asm(f"""call {c.AsmInp(handler6, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(6)
def isr39_handler() -> t.CExport | t.CVoid:
if pic.isSpurious(7):
return
handler7: irq_handler_t = irqGetHandler(7)
if handler7:
c.Asm(f"""call {c.AsmInp(handler7, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(7)
def isr40_handler() -> t.CExport | t.CVoid:
handler8: irq_handler_t = irqGetHandler(8)
if handler8:
c.Asm(f"""call {c.AsmInp(handler8, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(8)
def isr41_handler() -> t.CExport | t.CVoid:
handler9: irq_handler_t = irqGetHandler(9)
if handler9:
c.Asm(f"""call {c.AsmInp(handler9, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(9)
def isr42_handler() -> t.CExport | t.CVoid:
handler10: irq_handler_t = irqGetHandler(10)
if handler10:
c.Asm(f"""call {c.AsmInp(handler10, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(10)
def isr43_handler() -> t.CExport | t.CVoid:
handler11: irq_handler_t = irqGetHandler(11)
if handler11:
c.Asm(f"""call {c.AsmInp(handler11, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(11)
def isr44_handler() -> t.CExport | t.CVoid:
handler: irq_handler_t = irqGetHandler(12)
if handler:
c.Asm(f"""call {c.AsmInp(handler, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
pic.eoi(12)
def isr45_handler() -> t.CExport | t.CVoid: pic.eoi(13)
def isr46_handler() -> t.CExport | t.CVoid: pic.eoi(14)
def isr47_handler() -> t.CExport | t.CVoid:
if pic.isSpurious(15):
return
pic.eoi(15)
def init_exceptions():
setGate(0, t.CUInt64T(isr0), CODE_SEG, 0x8E)
setGate(1, t.CUInt64T(isr1), CODE_SEG, 0x8E)
setGate(2, t.CUInt64T(isr2), CODE_SEG, 0x8E)
setGate(3, t.CUInt64T(isr3), CODE_SEG, 0x8E)
setGate(4, t.CUInt64T(isr4), CODE_SEG, 0x8E)
setGate(5, t.CUInt64T(isr5), CODE_SEG, 0x8E)
setGate(6, t.CUInt64T(isr6), CODE_SEG, 0x8E)
setGate(7, t.CUInt64T(isr7), CODE_SEG, 0x8E)
setGate(8, t.CUInt64T(isr8), CODE_SEG, 0x8E)
setGate(9, t.CUInt64T(isr9), CODE_SEG, 0x8E)
setGate(10, t.CUInt64T(isr10), CODE_SEG, 0x8E)
setGate(11, t.CUInt64T(isr11), CODE_SEG, 0x8E)
setGate(12, t.CUInt64T(isr12), CODE_SEG, 0x8E)
setGate(13, t.CUInt64T(isr13), CODE_SEG, 0x8E)
setGate(14, t.CUInt64T(isr14), CODE_SEG, 0x8E)
setGate(15, t.CUInt64T(isr15), CODE_SEG, 0x8E)
setGate(16, t.CUInt64T(isr16), CODE_SEG, 0x8E)
setGate(17, t.CUInt64T(isr17), CODE_SEG, 0x8E)
setGate(18, t.CUInt64T(isr18), CODE_SEG, 0x8E)
setGate(19, t.CUInt64T(isr19), CODE_SEG, 0x8E)
setGate(20, t.CUInt64T(isr20), CODE_SEG, 0x8E)
setGate(21, t.CUInt64T(isr21), CODE_SEG, 0x8E)
setGate(22, t.CUInt64T(isr22), CODE_SEG, 0x8E)
setGate(23, t.CUInt64T(isr23), CODE_SEG, 0x8E)
setGate(24, t.CUInt64T(isr24), CODE_SEG, 0x8E)
setGate(25, t.CUInt64T(isr25), CODE_SEG, 0x8E)
setGate(26, t.CUInt64T(isr26), CODE_SEG, 0x8E)
setGate(27, t.CUInt64T(isr27), CODE_SEG, 0x8E)
setGate(28, t.CUInt64T(isr28), CODE_SEG, 0x8E)
setGate(29, t.CUInt64T(isr29), CODE_SEG, 0x8E)
setGate(30, t.CUInt64T(isr30), CODE_SEG, 0x8E)
setGate(31, t.CUInt64T(isr31), CODE_SEG, 0x8E)
def init_irqs():
setGate(32, t.CUInt64T(isr32), CODE_SEG, 0x8E)
setGate(33, t.CUInt64T(isr33), CODE_SEG, 0x8E)
setGate(34, t.CUInt64T(isr34), CODE_SEG, 0x8E)
setGate(35, t.CUInt64T(isr35), CODE_SEG, 0x8E)
setGate(36, t.CUInt64T(isr36), CODE_SEG, 0x8E)
setGate(37, t.CUInt64T(isr37), CODE_SEG, 0x8E)
setGate(38, t.CUInt64T(isr38), CODE_SEG, 0x8E)
setGate(39, t.CUInt64T(isr39), CODE_SEG, 0x8E)
setGate(40, t.CUInt64T(isr40), CODE_SEG, 0x8E)
setGate(41, t.CUInt64T(isr41), CODE_SEG, 0x8E)
setGate(42, t.CUInt64T(isr42), CODE_SEG, 0x8E)
setGate(43, t.CUInt64T(isr43), CODE_SEG, 0x8E)
setGate(44, t.CUInt64T(isr44), CODE_SEG, 0x8E)
setGate(45, t.CUInt64T(isr45), CODE_SEG, 0x8E)
setGate(46, t.CUInt64T(isr46), CODE_SEG, 0x8E)
setGate(47, t.CUInt64T(isr47), CODE_SEG, 0x8E)
irq_handlers: t.CStatic | t.CArray[irq_handler_t, 16] = [None]
def irqInstallHandler(irq: t.CInt, handler: irq_handler_t, name: str) -> t.CInt:
global irq_handlers
if irq < 0 or irq > 15: return -1
irq_handlers[irq] = handler
return 0
def irqGetHandler(irq: t.CInt) -> irq_handler_t:
if irq < 0 or irq > 15: return None
return irq_handlers[irq]
def init():
global idt
for i in range(256):
setGate(i, t.CUInt64T(isr_default), CODE_SEG, 0x8E)
pic.init()
init_exceptions()
init_irqs()
# Register ISR 0x80 for int 0x80 syscall interface (user-mode ELF apps)
setGate(0x80, t.CUInt64T(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
# Build idt_ptr on stack and load directly in one asm block
c.Asm("""lea rax, [rip + idt]
sub rsp, 16
mov word ptr [rsp], 0x0fff
mov qword ptr [rsp+2], rax
lidt [rsp]
add rsp, 16""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
-595
View File
@@ -1,595 +0,0 @@
.section .bss
.comm _per_cpu, 32, 8
.comm _proc_mgr, 8192, 16
.comm _proc_mgr_ptr, 8, 8
.comm _saved_cr3, 8, 8
.comm _yield_cnt, 4, 4
.comm _yield_lock, 4, 4
.comm _fs_lock, 4, 4
.comm _fault_rip, 8, 8
.comm _fault_err, 8, 8
.section .text
.intel_syntax noprefix
.globl isr_default
isr_default:
push rax
push rdx
mov al, 0x20
out 0xA0, al
out 0x20, al
pop rdx
pop rax
iretq
# =============================================================================
# ISR macros with Ring 3 support
#
# When CPU takes interrupt/exception:
# From Ring 0: pushes RFLAGS, CS, RIP (3 qwords)
# From Ring 3: pushes SS, RSP, RFLAGS, CS, RIP (5 qwords)
# CPU also switches to TSS RSP0 stack when coming from Ring 3.
#
# Strategy:
# 1. Check CS RPL to determine if from Ring 3
# 2. If from Ring 3: swapgs (make gs: point to per_cpu), save user RSP
# 3. Save full interrupt frame into registers
# 4. Re-push in uniform format with is_user flag
# 5. Call handler
# 6. On return, rebuild correct iretq frame based on is_user
# 7. If returning to Ring 3: swapgs back
# =============================================================================
.macro ISR_NOERR num
.globl isr\num
isr\num:
# Check CS RPL to determine if from Ring 3
mov rax, [rsp + 8] # CS from interrupt frame
test al, 3 # RPL bits: 0 = Ring 0, 3 = Ring 3
jnz isr\num\()_from_user
isr\num\()_from_kernel:
# From Ring 0: no swapgs needed, already on kernel stack
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 24 # remove the 3 CPU-pushed qwords
jmp isr\num\()_frame_ready
isr\num\()_from_user:
# From Ring 3: swapgs to make gs: accessible, CPU already switched to TSS RSP0
swapgs
# Save user RSP to per_cpu.user_rsp (gs:[0x0])
# Note: CPU has already switched RSP to TSS RSP0, so the user RSP is on this stack
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
mov rax, [rsp + 24] # RSP (user)
mov r11, [rsp + 32] # SS (user)
# Save user RSP to per_cpu for potential later use
mov gs:[0x0], rax
add rsp, 40 # remove the 5 CPU-pushed qwords
isr\num\()_frame_ready:
# r8=RIP, r9=CS, r10=RFLAGS, rax=RSP(0 if kernel), r11=SS(0 if kernel)
# Build uniform frame on stack for iretq later
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
# Push is_user flag (1 if from Ring 3, 0 if from Ring 0)
xor ecx, ecx
test r9b, 3 # test CS RPL
setnz cl # cl = 1 if from Ring 3
push rcx # is_user
# Push all general-purpose registers
push rax
push rbx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
# Save faulting RIP and error code for debug
mov [_fault_rip], r8
mov [_fault_err], rdx
call isr\num\()_handler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rbx
pop rax
# Pop is_user flag
pop rcx # is_user
# Pop the uniform frame into registers
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr\num\()_ret_user
isr\num\()_ret_kernel:
# Return to Ring 0: push RFLAGS, CS, RIP only
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr\num\()_ret_user:
# Return to Ring 3: swapgs back, then push SS, RSP, RFLAGS, CS, RIP
swapgs
# DIAG+FIX: if RFLAGS.NT (bit 14) is set, iretq performs hardware task-return
# which loads TSS selector 0x28 -> #GP(err=0x28). Detect and clear it.
test r10, 0x4000
jz 1f
btr r10, 14
mov dx, 0x3F8
mov al, 0x4E # 'N' marker = NT was set (now cleared)
out dx, al
1:
cmp r9, 0x1B
jne 8f
cmp r11, 0x23
jne 8f
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
8:
mov dx, 0x3F8
mov al, 0x42 # 'B' = bad CS/SS
out dx, al
mov al, 0x20 # space
out dx, al
# Output CS (r9) low byte as 2 hex digits
mov rcx, r9
mov rax, rcx
shr rax, 4
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 2f
add al, 7
2:
out dx, al
mov rax, rcx
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 3f
add al, 7
3:
out dx, al
mov al, 0x20 # space
out dx, al
# Output SS (r11) low byte as 2 hex digits
mov rcx, r11
mov rax, rcx
shr rax, 4
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 4f
add al, 7
4:
out dx, al
mov rax, rcx
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 5f
add al, 7
5:
out dx, al
mov al, 0x0A # newline
out dx, al
cli
7:
hlt
jmp 7b
.endm
.macro ISR_ERR num
.globl isr\num
isr\num:
# Stack at entry (with error code):
# From Ring 0: [rsp]=error_code, [rsp+8]=RIP, [rsp+16]=CS, [rsp+24]=RFLAGS
# From Ring 3: [rsp]=error_code, [rsp+8]=RIP, [rsp+16]=CS, [rsp+24]=RFLAGS, [rsp+32]=RSP, [rsp+40]=SS
# Check CS RPL
mov rax, [rsp + 16] # CS from interrupt frame
test al, 3
jnz isr\num\()_from_user
isr\num\()_from_kernel:
# From Ring 0: no swapgs needed
mov rdx, [rsp] # error_code
mov r8, [rsp + 8] # RIP
mov r9, [rsp + 16] # CS
mov r10, [rsp + 24] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 32 # remove 4 CPU-pushed qwords (error + 3 frame)
jmp isr\num\()_frame_ready
isr\num\()_from_user:
# From Ring 3: swapgs, CPU already on TSS RSP0
swapgs
mov rdx, [rsp] # error_code
mov r8, [rsp + 8] # RIP
mov r9, [rsp + 16] # CS
mov r10, [rsp + 24] # RFLAGS
mov rax, [rsp + 32] # RSP (user)
mov r11, [rsp + 40] # SS (user)
mov gs:[0x0], rax # save user RSP
add rsp, 48 # remove 6 CPU-pushed qwords (error + 5 frame)
isr\num\()_frame_ready:
# rdx=error_code, r8=RIP, r9=CS, r10=RFLAGS, rax=RSP, r11=SS
# Build uniform frame on stack
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
push rdx # error_code
# Push is_user flag
xor ecx, ecx
test r9b, 3
setnz cl
push rcx # is_user
# Push all general-purpose registers
push rax
push rbx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
# Save faulting RIP and error code for debug
mov [_fault_rip], r8
mov [_fault_err], rdx
call isr\num\()_handler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rbx
pop rax
# Pop is_user flag
pop rcx # is_user
add rsp, 8 # skip error_code (handler already consumed it)
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr\num\()_ret_user
isr\num\()_ret_kernel:
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr\num\()_ret_user:
swapgs
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
.endm
ISR_NOERR 0
ISR_NOERR 1
ISR_NOERR 2
ISR_NOERR 3
ISR_NOERR 4
ISR_NOERR 5
ISR_NOERR 6
ISR_NOERR 7
ISR_ERR 8
ISR_NOERR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR_NOERR 15
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
ISR_NOERR 20
ISR_NOERR 21
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_NOERR 29
ISR_NOERR 30
ISR_NOERR 31
ISR_NOERR 32
ISR_NOERR 33
ISR_NOERR 34
ISR_NOERR 35
ISR_NOERR 36
ISR_NOERR 37
ISR_NOERR 38
ISR_NOERR 39
ISR_NOERR 40
ISR_NOERR 41
ISR_NOERR 42
ISR_NOERR 43
ISR_NOERR 44
ISR_NOERR 45
ISR_NOERR 46
ISR_NOERR 47
.globl syscall_entry
syscall_entry:
mov rax, rsp
shr rax, 47
test rax, rax
jnz syscall_from_kernel
syscall_from_user:
swapgs
mov gs:[0x0], rsp
mov rsp, gs:[0x8]
jmp syscall_common
syscall_from_kernel:
syscall_common:
push rcx
push r11
push rbx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r12
push r13
push r14
push r15
mov rbp, rsp
and rsp, ~15
push r9
mov r9, r8
mov r8, r10
mov rcx, rdx
mov rdx, rsi
mov rsi, rdi
mov rdi, rax
call syscall_handler
add rsp, 8
mov rsp, rbp
pop r15
pop r14
pop r13
pop r12
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rbx
pop r11
pop rcx
mov rax, rcx
shr rax, 47
test rax, rax
jnz syscall_ret_kernel
syscall_ret_user:
mov rsp, gs:[0x0]
swapgs
push r11
popfq
sysretq
syscall_ret_kernel:
push r11
popfq
jmp rcx
# =============================================================================
# ISR 0x80 - int 0x80 syscall handler for user-mode ELF apps
#
# int 0x80 calling convention (ViperOS):
# rax = syscall number
# rbx = arg1
# rcx = arg2
# rdx = arg3
# r10 = arg4
#
# Translated to syscall_handler calling convention:
# rdi = n (syscall number)
# rsi = arg1
# rdx = arg2
# rcx = arg3
# r8 = arg4
# r9 = arg5 (0)
# stack = arg6 (0)
#
# Return value in rax.
# =============================================================================
.globl isr80
isr80:
# Check CS RPL to determine if from Ring 3
mov rax, [rsp + 8] # CS from interrupt frame
test al, 3
jnz isr80_from_user
isr80_from_kernel:
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 24
jmp isr80_frame_ready
isr80_from_user:
swapgs
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
mov rax, [rsp + 24] # RSP (user)
mov r11, [rsp + 32] # SS (user)
mov gs:[0x0], rax
add rsp, 40
isr80_frame_ready:
# Build uniform frame on stack
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
# Save ALL registers FIRST (including original rcx = arg2)
# Order: rax, rbx, rcx, rdx, rsi, rdi, rbp, r8, r9, r10, r11, r12, r13, r14, r15
push rax # [rsp+112] rax (syscall number)
push rbx # [rsp+104] rbx (arg1)
push rcx # [rsp+96] rcx (arg2)
push rdx # [rsp+88] rdx (arg3)
push rsi # [rsp+80]
push rdi # [rsp+72]
push rbp # [rsp+64]
push r8 # [rsp+56]
push r9 # [rsp+48]
push r10 # [rsp+40] r10 (arg4)
push r11 # [rsp+32]
push r12 # [rsp+24]
push r13 # [rsp+16]
push r14 # [rsp+8]
push r15 # [rsp+0]
# Calculate is_user from saved CS on stack
# CS is at [rsp + 15*8 + 16] = [rsp + 136]
mov rax, [rsp + 136] # CS from frame
xor ecx, ecx
test al, 3
setnz cl
push rcx # is_user (pushed AFTER all registers)
# Stack layout now:
# [rsp+0] = is_user
# [rsp+8] = r15 [rsp+16] = r14 [rsp+24] = r13 [rsp+32] = r12
# [rsp+40] = r11 [rsp+48] = r10 [rsp+56] = r9 [rsp+64] = r8
# [rsp+72] = rbp [rsp+80] = rdi [rsp+88] = rsi [rsp+96] = rdx
# [rsp+104] = rcx [rsp+112] = rbx [rsp+120] = rax
# Translate int 0x80 calling convention to syscall_handler convention
mov rdi, [rsp + 120] # original rax = syscall number -> rdi
mov rsi, [rsp + 112] # original rbx = arg1 -> rsi
mov rdx, [rsp + 104] # original rcx = arg2 -> rdx
mov rcx, [rsp + 96] # original rdx = arg3 -> rcx
mov r8, [rsp + 48] # original r10 = arg4 -> r8
xor r9, r9 # arg5 = 0
push 0 # arg6 = 0 (on stack)
call syscall_handler
add rsp, 8 # remove arg6
# Save return value by overwriting saved rax on stack
mov [rsp + 120], rax
# Pop is_user flag
pop rcx # is_user
# Restore registers
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx # restore original rcx (arg2)
pop rbx
pop rax # now has the return value
# Pop frame
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr80_ret_user
isr80_ret_kernel:
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr80_ret_user:
swapgs
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
-470
View File
@@ -1,470 +0,0 @@
import drivers.serial.uart.serial as serial
import services.desktop as desktop
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import sched.sched as sched
import sched.process as process
import viperlib
import string
import mm.mm as mm
import paging.paging as paging
import execrunner.elf as elf
import t, c
CREATE_WINDOW: t.CDefine = 1
DRAW_TEXT: t.CDefine = 2
EXIT: t.CDefine = 3
OPEN: t.CDefine = 4
CLOSE: t.CDefine = 5
READ: t.CDefine = 6
WRITE: t.CDefine = 7
SEEK: t.CDefine = 8
TELL: t.CDefine = 9
SIZE: t.CDefine = 10
MKDIR: t.CDefine = 11
REMOVE: t.CDefine = 12
OPENDIR: t.CDefine = 13
READDIR: t.CDefine = 14
CLOSEDIR: t.CDefine = 15
STAT: t.CDefine = 16
WAIT_WINDOW: t.CDefine = 17
SERIAL_PUTS: t.CDefine = 18
LOAD_SO: t.CDefine = 19
SO_CALL1: t.CDefine = 20
GET_WINBUF: t.CDefine = 21
WIN_FLUSH: t.CDefine = 22
POLL_EVENT: t.CDefine = 23
SET_CURSOR: t.CDefine = 24
YIELD: t.CDefine = 25
SET_TITLE: t.CDefine = 26
SET_GEOMETRY: t.CDefine = 27
SPAWN: t.CDefine = 28
MMAP: t.CDefine = 29
MUNMAP: t.CDefine = 30
SET_RESIZABLE: t.CDefine = 31
GET_WIN_SIZE: t.CDefine = 32
THREAD_CREATE: t.CDefine = 33
IA32_EFER: t.CDefine = 0xC0000080
IA32_STAR: t.CDefine = 0xC0000081
IA32_LSTAR: t.CDefine = 0xC0000082
IA32_FMASK: t.CDefine = 0xC0000084
def wrmsr(msr: t.CUInt32T, val: t.CUInt64T):
lo: t.CUInt32T = t.CUInt32T(val & 0xFFFFFFFF)
hi: t.CUInt32T = t.CUInt32T(val >> 32)
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(lo, t.ASM_DESCR.REG_ANY)}
mov edx, {c.AsmInp(hi, t.ASM_DESCR.REG_ANY)}
wrmsr""",
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
lo: t.CUInt32T
hi: t.CUInt32T
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
rdmsr""",
out=[c.AsmOut(lo, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
return t.CUInt64T(lo) | (t.CUInt64T(hi) << 32)
def _current_proc() -> process.Process | t.CPtr:
return process.ProcessManager.current()
def _fd_alloc(p: process.Process | t.CPtr) -> t.CInt:
for i in range(process.PROC_MAX_FDS):
if not p.fd_used[i]:
p.fd_used[i] = 1
return i
return -1
def _fd_free(p: process.Process | t.CPtr, fd: t.CInt):
if fd >= 0 and fd < process.PROC_MAX_FDS:
p.fd_used[fd] = 0
p.fd_table[fd] = t.CVoid(0, t.CPtr)
def _dir_alloc(p: process.Process | t.CPtr) -> t.CInt:
for i in range(process.PROC_MAX_DIRS):
if not p.dir_used[i]:
p.dir_used[i] = 1
return i
return -1
def _dir_free(p: process.Process | t.CPtr, dd: t.CInt):
if dd >= 0 and dd < process.PROC_MAX_DIRS:
p.dir_used[dd] = 0
p.dir_table[dd] = t.CVoid(0, t.CPtr)
def CREATE_WINDOW(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
desktop.set_app_pid(process.current())
return desktop.create(x, y, w, h, title, style)
def DRAW_TEXT(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
return desktop.draw_text(win_id, x, y, text, color)
def EXIT(code: t.CInt) -> t.CInt:
serial.puts("[syscall] exit called\n")
desktop.destroy_by_pid(process.current())
return 0
def WAIT_WINDOW(win_id: t.CInt) -> t.CInt:
while desktop.is_active(win_id):
sched.Scheduler.try_reschedule()
return 0
def SERIAL_PUTS(str_ptr: t.CVoid | t.CPtr) -> t.CInt:
s: t.CConst | t.CChar | t.CPtr = t.CVoid(str_ptr, t.CPtr)
serial.puts(s)
return 0
_loaded_so_base: t.CVoid | t.CPtr = None
_loaded_so_path: t.CArray[t.CChar, 64]
def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
global _loaded_so_base
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
serial.puts("[so] loading: ")
serial.puts(path)
serial.puts("\n")
base: t.CVoid | t.CPtr = elf.load_so(path)
if base is not None:
_loaded_so_base = base
for i in range(63):
ch: t.CChar = c.Deref(path + i)
_loaded_so_path[i] = ch
if ch == 0: break
_loaded_so_path[63] = 0
return t.CUInt64T(base)
return 0
def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
if _loaded_so_base is None: return -1
sym_name: t.CConst | t.CChar | t.CPtr = t.CVoid(sym_name_ptr, t.CPtr)
fn: t.CVoid | t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
if fn is None:
serial.puts("[so] symbol not found\n")
return -2
c.Asm(f"""mov rdi, {c.AsmInp(arg1, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(fn, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
serial.puts("[so] call returned\n")
return 0
def GET_WINBUF(win_id: t.CInt) -> t.CUInt64T:
buf: t.CVoid | t.CPtr = desktop.get_fb(win_id)
if buf is None:
return 0
return t.CUInt64T(buf)
def WIN_FLUSH(win_id: t.CInt) -> t.CInt:
desktop.flush(win_id)
return 0
def SET_CURSOR(win_id: t.CInt, cursor_t: t.CInt) -> t.CInt:
desktop.set_cursor_type(win_id, cursor_t)
return 0
def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
fp: t.CVoid | t.CPtr = fat32.open(path, t.CUInt8T(mode))
if not fp:
fat32.unlock()
return -1
fd: t.CInt = _fd_alloc(p)
if fd < 0:
fat32.close(fp)
fat32.unlock()
return -1
p.fd_table[fd] = fp
fat32.unlock()
return fd
def CLOSE(fd: t.CInt) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
res: t.CInt = t.CInt(fat32.close(fp))
fat32.unlock()
_fd_free(p, fd)
return res
def READ(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
br: t.CUInt32T = fat32.read(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(br)
def WRITE(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
bw: t.CUInt32T = fat32.write(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(bw)
def SEEK(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
r: t.CInt = t.CInt(fat32.seek(fp, offset))
fat32.unlock()
return r
def TELL(fd: t.CInt) -> t.CUInt32T:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
pos: t.CUInt32T = fat32.tell(fp)
fat32.unlock()
return pos
def fsize(fd: t.CInt) -> t.CUInt32T:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
sz: t.CUInt32T = fat32.size(fp)
fat32.unlock()
return sz
def MKDIR(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.mkdir(path))
fat32.unlock()
return r
def REMOVE(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.remove(path))
fat32.unlock()
return r
def OPENdir(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
dd: t.CInt = _dir_alloc(p)
if dd < 0:
return -1
dp: fat32_types.dirobj | t.CPtr = c.Addr(p.dir_pool[dd])
fat32.lock()
res: t.CInt = t.CInt(fat32.opendir(path, dp))
fat32.unlock()
if res != 0:
_dir_free(p, dd)
return -1
p.dir_table[dd] = t.CVoid(t.CUInt64T(dp), t.CPtr)
return dd
def READdir(dd: t.CInt, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.readdir(dp, info))
fat32.unlock()
return r
def CLOSEdir(dd: t.CInt) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
fat32.closedir(dp)
fat32.unlock()
_dir_free(p, dd)
return 0
def STAT(path_ptr: t.CVoid | t.CPtr, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.stat(path, info))
fat32.unlock()
return r
def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
pid: t.CInt = elf.spawn_elf(path)
if pid < 0:
return pid
if blocking:
p: process.Process | t.CPtr = process.ProcessManager.get_process(pid)
if p:
while p.state != process.PROC_DONE:
sched.Scheduler.try_reschedule()
return pid
USER_HEAP_BASE: t.CDefine = 0x20000000
def MMAP(size: t.CUInt64T) -> t.CUInt64T:
p: process.Process | t.CPtr = _current_proc()
if size == 0: return 0
aligned_size: t.CUInt64T = (size + 4095) & ~t.CUInt64T(4095)
if p.heap_start == 0:
p.heap_start = USER_HEAP_BASE
heap_end: t.CUInt64T = p.heap_start + p.heap_size
new_end: t.CUInt64T = heap_end + aligned_size
for va in range(heap_end, new_end, 4096):
phys_page: t.CVoid | t.CPtr = mm.malloc(4096)
if phys_page is None: return 0
paging.MapPage(va, t.CUInt64T(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned_size
return heap_end
def MUNMAP(ptr: t.CUInt64T, size: t.CUInt64T) -> t.CInt:
return 0
def syscall_entry() -> t.CExtern | t.CVoid | t.State: pass
def syscall_handler(num: t.CUInt64T, arg1: t.CUInt64T, arg2: t.CUInt64T, arg3: t.CUInt64T, arg4: t.CUInt64T, arg5: t.CUInt64T, arg6: t.CUInt64T) -> t.CExport | t.CUInt64T:
n: t.CInt = t.CInt(num)
if n == CREATE_WINDOW:
title_ptr: t.CVoid | t.CPtr = t.CVoid(arg5, t.CPtr)
return t.CUInt64T(CREATE_WINDOW(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), title_ptr, t.CInt(arg6)))
elif n == DRAW_TEXT:
text_ptr: t.CVoid | t.CPtr = t.CVoid(arg4, t.CPtr)
return t.CUInt64T(DRAW_TEXT(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), text_ptr, t.CUInt32T(arg5)))
elif n == EXIT:
return t.CUInt64T(EXIT(t.CInt(arg1)))
elif n == OPEN:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPEN(path_ptr, t.CUInt32T(arg2)))
elif n == CLOSE:
return t.CUInt64T(CLOSE(t.CInt(arg1)))
elif n == READ:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READ(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
elif n == WRITE:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(WRITE(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
elif n == SEEK:
return t.CUInt64T(SEEK(t.CInt(arg1), t.CUInt32T(arg2)))
elif n == TELL:
return t.CUInt64T(TELL(t.CInt(arg1)))
elif n == SIZE:
return t.CUInt64T(fsize(t.CInt(arg1)))
elif n == MKDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(MKDIR(path_ptr))
elif n == REMOVE:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(REMOVE(path_ptr))
elif n == OPENDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPENdir(path_ptr))
elif n == READDIR:
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READdir(t.CInt(arg1), info_ptr))
elif n == CLOSEDIR:
return t.CUInt64T(CLOSEdir(t.CInt(arg1)))
elif n == STAT:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(STAT(path_ptr, info_ptr))
elif n == WAIT_WINDOW:
if t.CInt(arg2) == 1:
return t.CUInt64T(desktop.is_active(t.CInt(arg1)))
elif t.CInt(arg2) == 2:
sched.Scheduler.try_reschedule()
return 0
return t.CUInt64T(WAIT_WINDOW(t.CInt(arg1)))
elif n == SERIAL_PUTS:
str_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SERIAL_PUTS(str_ptr_sp))
elif n == LOAD_SO:
path_ptr_so: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return LOAD_SO(path_ptr_so)
elif n == SO_CALL1:
sym_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SO_CALL1(sym_ptr, arg2))
elif n == GET_WINBUF:
return GET_WINBUF(t.CInt(arg1))
elif n == WIN_FLUSH:
return t.CUInt64T(WIN_FLUSH(t.CInt(arg1)))
elif n == POLL_EVENT:
buf_ptr_ev: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
caller_pid_ev: t.CInt = process.current()
return t.CUInt64T(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
elif n == SET_CURSOR:
desktop.set_cursor_type(t.CInt(arg1), t.CInt(arg2))
return 0
elif n == YIELD:
sched.Scheduler.try_reschedule()
return 0
elif n == SET_TITLE:
title_ptr_st: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(desktop.set_title(t.CInt(arg1), title_ptr_st))
elif n == SET_GEOMETRY:
return t.CUInt64T(desktop.set_geometry(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), t.CInt(arg5)))
elif n == SET_RESIZABLE:
return t.CUInt64T(desktop.set_resizable(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3)))
elif n == GET_WIN_SIZE:
return t.CUInt64T(desktop.get_size(t.CInt(arg1)))
elif n == SPAWN:
path_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SPAWN(path_ptr_sp, t.CInt(arg2)))
elif n == MMAP:
return MMAP(arg1)
elif n == MUNMAP:
return t.CUInt64T(MUNMAP(arg1, arg2))
elif n == THREAD_CREATE:
func_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
arg_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
cur_pid: t.CInt = process.current()
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(func_ptr, arg_ptr, cur_pid)
if th is None: return t.CUInt64T(0xFFFFFFFFFFFFFFFF)
p: process.Process | t.CPtr = process.ProcessManager.get_process(cur_pid)
if p:
p.addThread(th.tid)
return t.CUInt64T(th.tid)
return 0
def init():
efer: t.CUInt64T = rdmsr(IA32_EFER)
efer = efer | 1
wrmsr(IA32_EFER, efer)
star_val: t.CUInt64T = (t.CUInt64T(0x08) << 32) | (t.CUInt64T(0x1B) << 48)
wrmsr(IA32_STAR, star_val)
wrmsr(IA32_LSTAR, t.CUInt64T(syscall_entry))
wrmsr(IA32_FMASK, 0x200)
serial.puts("[syscall] MSR init done\n")
-764
View File
@@ -1,764 +0,0 @@
import bootinfo
import paging.paging as paging
import viperstring as string
import viperlib
import t, c
# 伙伴系统常量定义
MIN_BLOCK_SIZE: t.CDefine = 4096 # 最小块大小(4KB)
MAX_BLOCK_SIZE: t.CDefine = 268435456 # 最大块大小(256MB)
MAX_ORDER: t.CDefine = 18 # 最大阶数(2^18 = 262144)
# 内存块状态
BLOCK_FREE: t.CDefine = 0 # 空闲
BLOCK_USED: t.CDefine = 1 # 已使用
# 内存类型定义
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
# 内存区域结构
class memory_region(t.CStruct):
start: t.CUInt64T
end: t.CUInt64T
size: t.CUInt64T
type: t.CUInt32T
next: 'memory_region' | t.CPtr
# 全局内存区域链表
memory_regions: t.CStatic | memory_region | t.CPtr = None
# 内存块结构
class memory_block(t.CStruct):
size: t.CUInt64T # 块大小
state: t.CUInt8T # 块状态
order: t.CUInt8T # 块阶数
next: 'memory_block' | t.CPtr # 下一个块
prev: 'memory_block' | t.CPtr # 上一个块
# 伙伴系统结构
class __buddy_system(t.CStruct):
free_lists: t.CArray[memory_block | t.CPtr, MAX_ORDER + 1]
total_memory: t.CUInt64T # 总内存大小
used_memory: t.CUInt64T # 已使用内存大小
free_memory: t.CUInt64T # 空闲内存大小
start_addr: t.CVoid | t.CPtr # 内存起始地址
end_addr: t.CVoid | t.CPtr # 内存结束地址
SLAB_MAGIC: t.CDefine = 0x534C4142
SLAB_NUM_SIZES: t.CDefine = 6
SLAB_THRESHOLD: t.CDefine = 1024
class slab_page(t.CStruct):
magic: t.CUInt32T
obj_size: t.CUInt16T
free_count: t.CUInt16T
data_offset: t.CUInt16T
total_objs: t.CUInt16T
free_head: t.CVoid | t.CPtr
block_ptr: memory_block | t.CPtr
next: 'slab_page' | t.CPtr
prev: 'slab_page' | t.CPtr
# 4K对齐函数
def align_4k(addr: t.CUInt64T) -> t.CUInt64T:
return (addr + 0xFFF) & ~0xFFF
# 计算阶数
def get_order(size: t.CUInt64T) -> t.CStatic | t.CInt:
order: t.CInt = 0
while size > MIN_BLOCK_SIZE:
size >>= 1
order += 1
return order
# 计算块大小
def get_block_size(order: t.CInt) -> t.CStatic | t.CUInt64T:
return MIN_BLOCK_SIZE << order
@t.Object
class _BuddySystemObject:
# 全局伙伴系统实例
buddy: __buddy_system
# 初始化伙伴系统
def __init__(self, start_addr: t.CVoid | t.CPtr, size: t.CUInt64T):
for i in range(MAX_ORDER + 1):
self.buddy.free_lists[i] = None
self.buddy.total_memory = size
self.buddy.used_memory = 0
self.buddy.free_memory = size
self.buddy.start_addr = start_addr
self.buddy.end_addr = t.CVoid(t.CUInt64T(start_addr) + size, t.CPtr)
remaining: t.CUInt64T = size
cur_addr: t.CUInt64T = t.CUInt64T(start_addr)
while remaining >= MIN_BLOCK_SIZE:
order: t.CInt = 0
tmp: t.CUInt64T = remaining
while tmp > MIN_BLOCK_SIZE:
tmp >>= 1
order += 1
block_size: t.CUInt64T = get_block_size(order)
while block_size > remaining and order > 0:
order -= 1
block_size = get_block_size(order)
if block_size > remaining: break
block: memory_block | t.CPtr = cur_addr
block.size = block_size
block.state = BLOCK_FREE
block.order = order
block.next = None
block.prev = None
if order <= MAX_ORDER:
if self.buddy.free_lists[order]:
block.next = self.buddy.free_lists[order]
self.buddy.free_lists[order].prev = block
self.buddy.free_lists[order] = block
cur_addr += block_size
remaining -= block_size
# DEBUG: print free_lists status after init
import drivers.serial.uart.serial as serial
_dmsg: t.CArray[t.CChar, 40]
serial.puts("[mm] buddy init:")
_di: t.CInt = 0
while _di <= MAX_ORDER:
if self.buddy.free_lists[_di]:
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, t.CUInt64T(self.buddy.free_lists[_di]))
serial.puts(_dmsg)
_di += 1
serial.puts("\n")
# 分割内存块
def split_block(self, block: memory_block | t.CPtr, target_order: t.CInt) -> memory_block | t.CPtr:
current_order: t.CInt = block.order
# 从当前阶数向下分割,直到达到目标阶数
while current_order > target_order:
current_order -= 1
new_block_size: t.CUInt64T = get_block_size(current_order)
# 创建新块
new_block: memory_block | t.CPtr = t.CUInt64T(block) + new_block_size
new_block.size = new_block_size
new_block.state = BLOCK_FREE
new_block.order = current_order
new_block.next = None
new_block.prev = None
# 更新原块大小和阶数
block.size = new_block_size
block.order = current_order
# 将新块添加到对应阶数的空闲链表
if current_order <= MAX_ORDER:
new_block.next = self.buddy.free_lists[current_order]
if self.buddy.free_lists[current_order]:
self.buddy.free_lists[current_order].prev = new_block
self.buddy.free_lists[current_order] = new_block
return block
# 合并内存块
def merge_blocks(self, block: memory_block | t.CPtr) -> t.CStatic | memory_block | t.CPtr:
order: t.CInt = block.order
while order < MAX_ORDER:
block_size: t.CUInt64T = get_block_size(order)
block_addr: t.CUInt64T = t.CUInt64T(block) - t.CUInt64T(self.buddy.start_addr)
buddy_addr: t.CUInt64T = block_addr ^ block_size
# 计算伙伴块地址
buddy: memory_block | t.CPtr = t.CUInt64T(self.buddy.start_addr) + buddy_addr
# 检查伙伴块是否存在且空闲
if buddy >= (memory_block | t.CPtr)(self.buddy.end_addr):
break # 伙伴块超出内存范围
if buddy.state != BLOCK_FREE or buddy.order != order:
break # 伙伴块不空闲或阶数不匹配
# 从空闲链表中移除伙伴块
if buddy.prev: buddy.prev.next = buddy.next
else: self.buddy.free_lists[order] = buddy.next
if buddy.next:
buddy.next.prev = buddy.prev
# 合并块
merged_block: memory_block | t.CPtr = block if block < buddy else buddy
merged_block.size = get_block_size(order + 1)
merged_block.order = order + 1
block = merged_block
order += 1
return block
# 分配内存块
def allocate_block(self, size: t.CUInt64T) -> t.CStatic | memory_block | t.CPtr:
# 计算所需阶数
order: t.CInt = get_order(size)
if order > MAX_ORDER: return None # 所需块大小超过最大限制
# 查找合适的空闲块
found_order: t.CInt = -1
for i in range(order, MAX_ORDER + 1):
if self.buddy.free_lists[i]:
found_order = i
break
# DEBUG: trace allocate_block
import drivers.serial.uart.serial as serial
_dba: t.CArray[t.CChar, 120]
if found_order == -1:
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc FAIL size=%lu order=%d\n", size, order)
serial.puts(_dba)
_dbf: t.CArray[t.CChar, 200]
_fi: t.CInt = 0
_fo: t.CInt = 0
while _fi <= MAX_ORDER:
if self.buddy.free_lists[_fi]:
_fs: t.CInt = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, t.CUInt64T(self.buddy.free_lists[_fi]))
_fo = _fo + _fs
_fi += 1
if _fo == 0:
serial.puts("[mm] all free_lists EMPTY\n")
else:
serial.puts(_dbf)
serial.puts("\n")
return None
if found_order == -1: return None # 没有合适的空闲块
# 取出空闲块
block: memory_block | t.CPtr = self.buddy.free_lists[found_order]
# 从空闲链表中移除块
if block.next: block.next.prev = None
self.buddy.free_lists[found_order] = block.next
# 如果块大小大于所需大小,分割块
if found_order > order:
block = self.split_block(block, order)
# 标记块为已使用
block.state = BLOCK_USED
# 更新内存统计
self.buddy.used_memory += block.size
self.buddy.free_memory -= block.size
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, t.CUInt64T(block))
serial.puts(_dba)
return block
# 释放内存块
def free_block(self, block: memory_block | t.CPtr) -> t.CStatic | t.CVoid:
# 标记块为空闲
block.state = BLOCK_FREE
# 更新内存统计
self.buddy.used_memory -= block.size
self.buddy.free_memory += block.size
# 尝试合并块
block = self.merge_blocks(block)
# 将块添加到对应阶数的空闲链表
order: t.CInt = block.order
if order <= MAX_ORDER:
block.next = self.buddy.free_lists[order]
block.prev = None
if self.buddy.free_lists[order]:
self.buddy.free_lists[order].prev = block
self.buddy.free_lists[order] = block
BuddySystemObject: _BuddySystemObject
def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
if size_class == 0: return 32
if size_class == 1: return 64
if size_class == 2: return 128
if size_class == 3: return 256
if size_class == 4: return 512
return 1024
def _slab_size_class(size: t.CUInt64T) -> t.CInt:
if size <= 32: return 0
if size <= 64: return 1
if size <= 128: return 2
if size <= 256: return 3
if size <= 512: return 4
if size <= 1024: return 5
return -1
def _slab_read_ptr(addr: t.CVoid | t.CPtr) -> t.CVoid | t.CPtr:
result: t.CVoid | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return result
def _slab_write_ptr(addr: t.CVoid | t.CPtr, val: t.CVoid | t.CPtr):
c.Asm(f"""mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
def _slab_find_page(ptr: t.CVoid | t.CPtr) -> slab_page | t.CPtr:
if ptr is None: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page_addr: t.CUInt64T = t.CUInt64T(ptr) & ~t.CUInt64T(0xFFF)
page: slab_page | t.CPtr = page_addr + hdr_off
if page.magic == SLAB_MAGIC:
os: t.CUInt16T = page.obj_size
if os == 32 or os == 64 or os == 128 or os == 256 or os == 512 or os == 1024:
return page
page_addr2: t.CUInt64T = page_addr - 4096
page2: slab_page | t.CPtr = page_addr2 + hdr_off
if page2.magic == SLAB_MAGIC:
os2: t.CUInt16T = page2.obj_size
if os2 == 32 or os2 == 64 or os2 == 128 or os2 == 256 or os2 == 512 or os2 == 1024:
return page2
return None
@t.Object
class _SlabAllocator:
caches: t.CArray[slab_page | t.CPtr, SLAB_NUM_SIZES]
def __init__(self):
for i in range(SLAB_NUM_SIZES):
self.caches[i] = None
def _create_page(self, size_class: t.CInt) -> slab_page | t.CPtr:
obj_size: t.CUInt16T = _slab_obj_size(size_class)
aligned_size: t.CUInt16T = t.CUInt16T((obj_size + 15) & ~15)
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(4096 + memory_block.__sizeof__())
if not block: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page: slab_page | t.CPtr = t.CUInt64T(block) + hdr_off
page.magic = SLAB_MAGIC
page.obj_size = aligned_size
d_off: t.CUInt16T = t.CUInt16T((hdr_off + slab_page.__sizeof__() + 15) & ~15)
page.data_offset = d_off
total: t.CUInt16T = t.CUInt16T((block.size - d_off) / aligned_size)
page.total_objs = total
page.free_count = total
page.block_ptr = block
page.next = None
page.prev = None
data_start: t.CUInt64T = t.CUInt64T(block) + d_off
page.free_head = t.CVoid(data_start, t.CPtr)
for i in range(1, total):
cur: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i - 1) * aligned_size, t.CPtr)
nxt: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i) * aligned_size, t.CPtr)
_slab_write_ptr(cur, nxt)
last: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(total - 1) * aligned_size, t.CPtr)
_slab_write_ptr(last, t.CVoid(0, t.CPtr))
return page
def alloc(self, size_class: t.CInt) -> t.CVoid | t.CPtr:
page: slab_page | t.CPtr = self.caches[size_class]
while page:
if page.free_count > 0: break
page = page.next
if not page:
page = self._create_page(size_class)
if not page: return None
page.next = self.caches[size_class]
if self.caches[size_class]:
self.caches[size_class].prev = page
self.caches[size_class] = page
obj: t.CVoid | t.CPtr = page.free_head
page.free_head = _slab_read_ptr(obj)
page.free_count -= 1
return obj
def free_obj(self, ptr: t.CVoid | t.CPtr, page: slab_page | t.CPtr):
_slab_write_ptr(ptr, page.free_head)
page.free_head = ptr
page.free_count += 1
if page.free_count == page.total_objs:
if page.prev:
page.prev.next = page.next
else:
sc: t.CInt = _slab_size_class(page.obj_size)
if sc >= 0:
self.caches[sc] = page.next
if page.next:
page.next.prev = page.prev
page.magic = 0
BuddySystemObject.free_block(page.block_ptr)
SlabAllocator: _SlabAllocator
# 内存分配函数
def malloc(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if size == 0: return None
if size <= SLAB_THRESHOLD:
sc: t.CInt = _slab_size_class(size)
if sc >= 0:
result: t.CVoid | t.CPtr = SlabAllocator.alloc(sc)
return result
hdr: t.CUInt64T = memory_block.__sizeof__()
if size >= 4096:
total: t.CUInt64T = size + 4096
total = align_4k(total)
order: t.CInt = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
import drivers.serial.uart.serial as serial
_dbm: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, t.CUInt64T(block))
serial.puts(_dbm)
if not block: return None
user_ptr: t.CUInt64T = (t.CUInt64T(block) + hdr + 4095) & ~t.CUInt64T(4095)
real_hdr: t.CUInt64T = user_ptr - 8
c.Asm(f"""mov rax, {c.AsmInp(block, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc ret user_ptr=0x%lx\n", user_ptr)
serial.puts(_dbm)
return t.CVoid(user_ptr, t.CPtr)
total2: t.CUInt64T = size + hdr
total2 = align_4k(total2)
order2: t.CInt = get_order(total2)
if order2 > MAX_ORDER: return None
block2: memory_block | t.CPtr = BuddySystemObject.allocate_block(total2)
if not block2: return None
return t.CVoid(t.CUInt64T(block2) + hdr, t.CPtr)
def malloc_direct(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if size == 0: return None
hdr: t.CUInt64T = memory_block.__sizeof__()
total: t.CUInt64T = size + hdr
total = align_4k(total)
order: t.CInt = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
if not block: return None
return t.CVoid(t.CUInt64T(block) + hdr, t.CPtr)
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
if ptr is None: return
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
SlabAllocator.free_obj(ptr, sp)
return
if (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr: t.CUInt64T = t.CUInt64T(ptr) - 8
block: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
BuddySystemObject.free_block(block)
return
block2: memory_block | t.CPtr = t.CUInt64T(ptr) - memory_block.__sizeof__()
BuddySystemObject.free_block(block2)
def calloc(nmemb: t.CUInt64T, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
total_size: t.CUInt64T = nmemb * size
ptr: t.CVoid | t.CPtr = malloc(total_size)
if ptr:
string.memset(ptr, 0, total_size)
return ptr
def realloc(ptr: t.CVoid | t.CPtr, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
new_ptr: t.CVoid | t.CPtr = malloc(size)
if not new_ptr: return None
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
old_size: t.CUInt64T = sp.obj_size
elif (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr_r: t.CUInt64T = t.CUInt64T(ptr) - 8
block_r: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr_r, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block_r, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
old_size = block_r.size - 4096
else:
block2: memory_block | t.CPtr = t.CUInt64T(ptr) - memory_block.__sizeof__()
old_size = block2.size - memory_block.__sizeof__()
copy_size: t.CUInt64T = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
# 回收内存区域链表
def free_memory_regions() -> t.CStatic | t.CVoid:
global memory_regions
current: memory_region | t.CPtr = memory_regions
while current:
next_region: memory_region | t.CPtr = current.next
free(current)
current = next_region
memory_regions = None
# 初始化内存管理系统
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt64T, FbAddr: t.CUInt64T = 0, FbSize: t.CUInt64T = 0):
global BuddySystemObject
import drivers.serial.uart.serial as serial
start_addr: t.CVoid | t.CPtr = None
size: t.CUInt64T = 0
if MemmapAddr != 0:
if MemmapSize > 0:
if MemmapDescSize > 0:
num_entries: t.CUInt64T = MemmapSize / MemmapDescSize
max_memory: t.CUInt64T = 0
best_start: t.CUInt64T = 0
best_avail_size: t.CUInt64T = 0
best_avail_start: t.CUInt64T = 0
best_bs_size: t.CUInt64T = 0
best_bs_start: t.CUInt64T = 0
best_ld_size: t.CUInt64T = 0
best_ld_start: t.CUInt64T = 0
i: t.CUInt64T
for i in range(num_entries):
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
etype: t.CUInt64T = entry.type
start: t.CUInt64T = align_4k(entry.physical_start)
np: t.CUInt64T = entry.num_pages
end: t.CUInt64T = entry.physical_start + np * 4096
end = align_4k(end - 1)
region_size: t.CUInt64T = end - start
if FbAddr != 0 and FbSize != 0:
fb_end: t.CUInt64T = FbAddr + FbSize
if start < fb_end and end > FbAddr:
continue
if etype == MEMORY_TYPE_AVAILABLE:
if region_size > best_avail_size:
best_avail_size = region_size
best_avail_start = start
if etype == MEMORY_TYPE_BOOT_SERVICES_DATA:
if region_size > best_bs_size:
best_bs_size = region_size
best_bs_start = start
if etype == MEMORY_TYPE_LOADER_DATA:
if region_size > best_ld_size:
best_ld_size = region_size
best_ld_start = start
min_blk: t.CUInt64T = MIN_BLOCK_SIZE
if best_avail_size >= min_blk:
best_start = best_avail_start
max_memory = best_avail_size
elif best_bs_size >= min_blk:
best_start = best_bs_start
max_memory = best_bs_size
elif best_ld_size >= min_blk:
best_start = best_ld_start
max_memory = best_ld_size
cr4: t.CArray[t.CChar, 128]
string.memset(c.Addr(cr4), 0, 128)
viperlib.snprintf(c.Addr(cr4), 128, "mm: best=0x%lx max=%lu entries=%lu avail=%lu bs=%lu ld=%lu\n",
best_start, max_memory, num_entries, best_avail_size, best_bs_size, best_ld_size)
serial.puts(cr4)
if best_start != 0:
if max_memory >= min_blk:
start_addr = t.CVoid(best_start, t.CPtr)
size = max_memory
if start_addr is None:
size = detect_memory_size()
size = align_4k(size)
# 起始地址 4MB(内核之后),避免超出物理 RAM
# 旧值 0x10000000 在 256MB QEMU 中超出物理 RAM 边界
start_addr = t.CVoid(align_4k(0x400000), t.CPtr)
if size > 0x400000:
size = size - 0x400000
size = align_4k(size)
min_blk2: t.CUInt64T = MIN_BLOCK_SIZE
if size < min_blk2:
size = 33554432
cr2: t.CArray[t.CChar, 128]
string.memset(c.Addr(cr2), 0, 128)
viperlib.snprintf(c.Addr(cr2), 128, "mm.init: start=0x%lx size=%lu bytes\n",
t.CUInt64T(start_addr), size)
serial.puts(cr2)
BuddySystemObject.__init__(start_addr, size)
SlabAllocator.__init__()
# 虚拟内存映射结构
class vm_area(t.CStruct):
VirtAddr: t.CUInt64T
PhysAddr: t.CUInt64T
size: t.CUInt64T
flags: t.CUInt32T
next: 'vm_area' | t.CPtr
# 全局虚拟内存区域链表
vm_areas: vm_area | t.CPtr = None
# 博弈机制参数
ALLOCATION_RETRIES: t.CDefine = 5 # 分配重试次数
FRAGMENTATION_THRESHOLD: t.CDefine = 0.7 # 碎片率阈值
# 获取内存使用统计
@c.CReturn(t.CUInt64T, t.CUInt64T, t.CUInt64T)
def GetMemoryStats():
return (BuddySystemObject.buddy.total_memory, BuddySystemObject.buddy.used_memory, BuddySystemObject.buddy.free_memory)
# 计算内存碎片率
def calculate_fragmentation() -> t.CDouble:
# 计算空闲块的数量和总大小
free_blocks: t.CInt = 0
free_size: t.CUInt64T = 0
for i in range(MAX_ORDER + 1):
block: memory_block | t.CPtr = BuddySystemObject.buddy.free_lists[i]
while block:
free_blocks += 1
free_size += block.size
block = block.next
# 如果没有空闲内存,返回0
if free_size == 0:
return 0.0
# 计算碎片率
# 碎片率 = 1 - (最大空闲块大小 / 总空闲内存大小)
max_free_block: t.CUInt64T = 0
for i in range(MAX_ORDER, -1, -1):
if BuddySystemObject.buddy.free_lists[i]:
max_free_block = get_block_size(i)
break
if max_free_block == 0:
return 1.0
return 1.0 - (t.CDouble(max_free_block) / t.CDouble(free_size))
# 内存整理函数
def compact_memory() -> t.CStatic | t.CInt:
freed_pages: t.CInt = 0
for sc in range(SLAB_NUM_SIZES):
page: slab_page | t.CPtr = SlabAllocator.caches[sc]
while page:
next_page: slab_page | t.CPtr = page.next
if page.free_count == page.total_objs:
if page.prev:
page.prev.next = page.next
else:
SlabAllocator.caches[sc] = page.next
if page.next:
page.next.prev = page.prev
page.magic = 0
BuddySystemObject.free_block(page.block_ptr)
freed_pages += 1
page = next_page
return freed_pages
# 虚拟内存分配函数
def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
global vm_areas
# 4K对齐
size = align_4k(size)
# 尝试分配物理内存,使用博弈机制
PhysAddr: t.CVoid | t.CPtr = None
retries: t.CInt = 0
while retries < ALLOCATION_RETRIES:
PhysAddr = malloc(size)
if PhysAddr:
break
# 内存不足,尝试进行内存整理
if calculate_fragmentation() > FRAGMENTATION_THRESHOLD:
compact_memory()
retries += 1
if not PhysAddr:
return 0
# 分配虚拟地址
# 简单的虚拟地址分配策略:从0x100000000开始
VirtAddr: t.CUInt64T = 0x100000000
current: vm_area | t.CPtr = vm_areas
# 寻找合适的虚拟地址空间
while current:
if VirtAddr + size <= current.VirtAddr:
break
VirtAddr = current.VirtAddr + current.size
current = current.next
# 创建虚拟内存区域
area: vm_area | t.CPtr = malloc(vm_area.__sizeof__())
if area:
area.VirtAddr = VirtAddr
area.PhysAddr = t.CUInt64T(PhysAddr)
area.size = size
area.flags = flags
area.next = vm_areas
vm_areas = area
# 映射虚拟地址到物理地址
# 计算需要映射的页数
pages: t.CUInt64T = size / 4096
i: t.CUInt64T
for i in range(pages):
page_virt: t.CUInt64T = VirtAddr + (i * 4096)
page_phys: t.CUInt64T = t.CUInt64T(PhysAddr) + (i * 4096)
# 调用paging模块的映射函数
paging.MapPage(page_virt, page_phys, flags)
return VirtAddr
# 虚拟内存释放函数
def vm_free(VirtAddr: t.CUInt64T):
global vm_areas
# 查找虚拟内存区域
current: vm_area | t.CPtr = vm_areas
prev: vm_area | t.CPtr = None
while current:
if current.VirtAddr == VirtAddr:
# 取消虚拟地址映射
pages: t.CUInt64T = current.size / 4096
i: t.CUInt64T
for i in range(pages):
page_virt: t.CUInt64T = current.VirtAddr + (i * 4096)
paging.UnMapPage(page_virt)
# 释放物理内存
free(t.CVoid(current.PhysAddr, t.CPtr))
if prev:
prev.next = current.next
else:
vm_areas = current.next
free(current)
return
prev = current
current = current.next
# CMOS读取函数
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
c.Asm(f"mov al, {c.AsmInp(reg)}\nout 0x70, al")
val: t.CUInt8T
c.Asm(f"in al, 0x71\nmov {c.AsmOut(val)}, al")
return val
# 内存大小测试函数
def detect_memory_size() -> t.CUInt64T:
# 读取 1MB-16MB 扩展内存(KB 单位)
low: t.CUInt8T = cmos_read(0x15)
high: t.CUInt8T = cmos_read(0x16)
mem_kb: t.CUInt32T = (t.CUInt32T(high) << 8) | low
# 读取 16MB 以上扩展内存(64KB 块为单位)
low2: t.CUInt8T = cmos_read(0x17)
high2: t.CUInt8T = cmos_read(0x18)
mem_above_16mb: t.CUInt32T = (t.CUInt32T(high2) << 8) | low2
# 两个寄存器都为 0 时使用默认值
if mem_kb == 0 and mem_above_16mb == 0:
return 0x10000000 # 256MB
# 计算总内存:1MB 基础 + 1MB-16MB + 16MB 以上
total_size: t.CUInt64T = 1048576 # 前 1MB
if mem_kb > 0:
total_size = total_size + t.CUInt64T(mem_kb) * 1024
if mem_above_16mb > 0:
total_size = total_size + t.CUInt64T(mem_above_16mb) * 65536
total_size = align_4k(total_size)
# 确保内存大小至少为32MB
if total_size < 33554432: # 32MB
total_size = 33554432
return total_size
-296
View File
@@ -1,296 +0,0 @@
import drivers.serial.uart.serial as serial
import viperlib
import t, c
PTE_PRESENT: t.CDefine = (1 << 0)
PTE_WRITABLE: t.CDefine = (1 << 1)
PTE_USER: t.CDefine = (1 << 2)
PTE_PWT: t.CDefine = (1 << 3)
PTE_PCD: t.CDefine = (1 << 4)
PTE_ACCESSED: t.CDefine = (1 << 5)
PTE_DIRTY: t.CDefine = (1 << 6)
PTE_PS: t.CDefine = (1 << 7)
PTE_GLOBAL: t.CDefine = (1 << 8)
class _p:
entries: t.CArray[t.CUInt64T, 512]
PT_POOL_PAGES: t.CDefine = 512
pt_pool_raw: t.CVoid | t.CPtr = None
pt_pool_start: t.CUInt64T = 0
pt_pool_used: t.CUInt64T = 0
AllocatedPages: t.CUInt64T = 0
pml4: _p | t.CPtr = None
pdp: _p | t.CPtr
pd: _p | t.CPtr
pt: _p | t.CPtr
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T):
global pml4
pml4 = GetCurrentPml4()
c.Asm(f"""
mov rax, cr0
and rax, ~0x10000
mov cr0, rax
""")
def init_pool(buf: t.CVoid | t.CPtr, buf_size: t.CUInt64T):
global pt_pool_raw, pt_pool_start, pt_pool_used
pt_pool_raw = buf
if buf is None: return
raw_addr: t.CUInt64T = t.CUInt64T(buf)
aligned_addr: t.CUInt64T = (raw_addr + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
pt_pool_start = aligned_addr
pt_pool_used = 0
def AllocPage() -> t.CVoid | t.CPtr:
global AllocatedPages, pt_pool_used, pml4, pdp, pd, pt
if pt_pool_raw is None: return None
if pt_pool_used >= t.CUInt64T(PT_POOL_PAGES): return None
page: t.CVoid | t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * t.CUInt64T(4096), t.CPtr)
pt_pool_used = pt_pool_used + t.CUInt64T(1)
c.Asm(f"""mov al, 0
mov ecx, 4096
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
AllocatedPages = AllocatedPages + t.CUInt64T(1)
return page
def FreePage(page: t.CVoid | t.CPtr):
global AllocatedPages, pml4, pdp, pd, pt
if page is None: return
if AllocatedPages > t.CUInt64T(0): AllocatedPages = AllocatedPages - t.CUInt64T(1)
def MapPage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0 or PhysAddr == 0: return
VirtAddr = VirtAddr & ~t.CUInt64T(0xFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0xFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if pd.entries[PdIndex] & 1:
if pd.entries[PdIndex] & 0x80:
big_phys: t.CUInt64T = pd.entries[PdIndex] & ~t.CUInt64T(0x1FFFFF)
inherit_flags: t.CUInt64T = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
pt: _p | t.CPtr = AllocPage()
if not pt: return
split_i: t.CInt = 0
while split_i < 512:
pt.entries[split_i] = (big_phys + t.CUInt64T(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
# PD entry exists as a regular PT (e.g. cloned identity mapping).
# Must propagate PTE_USER to the PD entry so user-mode access is
# allowed at all paging levels, otherwise #PF err=0x5.
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
else:
pt: _p | t.CPtr = AllocPage()
if not pt: return
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def MapLargePage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T) -> t.CVoid:
global pml4, pdp, pd, pt
VirtAddr = VirtAddr & ~t.CUInt64T(0x1FFFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0x1FFFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not pml4.entries[Pml4Index] & PTE_PRESENT:
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def UnMapPage(VirtAddr: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0: return
if not pml4: return
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pd.entries[PdIndex] & PTE_PRESENT: return
if pd.entries[PdIndex] & PTE_PS:
pd.entries[PdIndex] = 0
else:
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = 0
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def EnablePaging():
global pml4, pdp, pd, pt
c.Asm(f"mov cr3, {c.AsmInp(t.CUInt64T(pml4), t.ASM_DESCR.REG_ANY)}")
def GetCurrentPml4() -> _p | t.CPtr:
global pml4, pdp, pd, pt
cr3: t.CUInt64T
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
return (_p | t.CPtr)(cr3 & ~t.CUInt64T(0xFFF))
def create_process_page_table() -> t.CUInt64T:
global pml4
if not pml4: return 0
new_pml4: _p | t.CPtr = AllocPage()
if not new_pml4: return 0
i: t.CUInt64T
for i in range(512):
entry: t.CUInt64T = pml4.entries[i]
if entry & PTE_PRESENT:
new_pml4.entries[i] = entry
return t.CUInt64T(new_pml4)
def clone_for_process(isolate_vaddr: t.CUInt64T) -> t.CUInt64T:
global pml4
_dbg: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", t.CUInt64T(pml4), pt_pool_used, isolate_vaddr)
serial.puts(_dbg)
if not pml4: return 0
new_pml4_page: _p | t.CPtr = AllocPage()
if not new_pml4_page:
serial.puts("[clone] AllocPage pml4 failed\n")
return 0
_dbg2: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", t.CUInt64T(new_pml4_page))
serial.puts(_dbg2)
i: t.CUInt64T
for i in range(512):
new_pml4_page.entries[i] = pml4.entries[i]
pml4_idx: t.CUInt64T = (isolate_vaddr >> 39) & 0x1FF
_dbg3: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
serial.puts(_dbg3)
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pdp_page: _p | t.CPtr = AllocPage()
if not new_pdp_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pdp_page.entries[i] = kernel_pdp.entries[i]
new_pml4_page.entries[pml4_idx] = (t.CUInt64T(new_pdp_page) & ~t.CUInt64T(0xFFF)) | (pml4.entries[pml4_idx] & t.CUInt64T(0xFFF))
pdp_idx: t.CUInt64T = (isolate_vaddr >> 30) & 0x1FF
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pd_page: _p | t.CPtr = AllocPage()
if not new_pd_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pd_page.entries[i] = kernel_pd.entries[i]
new_pdp_page.entries[pdp_idx] = (t.CUInt64T(new_pd_page) & ~t.CUInt64T(0xFFF)) | (kernel_pdp.entries[pdp_idx] & t.CUInt64T(0xFFF))
pd_idx: t.CUInt64T = (isolate_vaddr >> 21) & 0x1FF
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
if kernel_pd.entries[pd_idx] & PTE_PS: return t.CUInt64T(new_pml4_page)
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pt_page: _p | t.CPtr = AllocPage()
if not new_pt_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pt_page.entries[i] = kernel_pt.entries[i]
new_pd_page.entries[pd_idx] = (t.CUInt64T(new_pt_page) & ~t.CUInt64T(0xFFF)) | (kernel_pd.entries[pd_idx] & t.CUInt64T(0xFFF))
return t.CUInt64T(new_pml4_page)
def save_pt_range(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T, save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T | t.CPtr) -> t.CInt:
global pml4
if not pml4: return -1
c.Set(save_count, t.CUInt32T(0))
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
while va < vaddr_end:
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
saved: t.CUInt32T = c.DerefAs(save_count) # 此处操作意义存疑?
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(saved) * 16
c.DerefAs(entry_ptr, va)
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
c.Set(save_count, t.CUInt32T(saved + 1))
va += 0x1000
return 0
def restore_pt_range(save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T):
global pml4
if not pml4: return
i: t.CUInt32T = 0
while i < save_count:
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(i) * 16
va: t.CUInt64T = c.DerefAs(entry_ptr)
orig_pte: t.CUInt64T = c.DerefAs(entry_ptr + 8)
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
pt_.entries[pt_idx] = orig_pte
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
i += 1
def set_active_pml4(cr3_val: t.CUInt64T):
global pml4
pml4 = t.CType(cr3_val & ~t.CUInt64T(0xFFF), _p, t.CPtr)
-4
View File
@@ -1,4 +0,0 @@
from . import pic
from . import pit
from . import timer
from . import rtc
-120
View File
@@ -1,120 +0,0 @@
import asm
import t, c
# PIC端口定义
PIC1_COMMAND: t.CDefine = 0x20
PIC1_DATA: t.CDefine = 0x21
PIC2_COMMAND: t.CDefine = 0xA0
PIC2_DATA: t.CDefine = 0xA1
# ICW1 - 初始化命令字1
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
ICW1_INIT: t.CDefine = 0x10 # 初始化
# ICW4 - 初始化命令字4
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
# OCW2 - 操作命令字2
OCW2_EOI: t.CDefine = 0x20 # 结束中断
# OCW3 - 操作命令字3
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
# 初始化PIC
def init():
# 发送ICW1:开始初始化,需要ICW4
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
# 发送ICW2:中断向量偏移
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
asm.io_wait()
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
asm.io_wait()
# 发送ICW3:级联信息
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
asm.io_wait()
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
asm.io_wait()
# 发送ICW4:8086模式
asm.outb(PIC1_DATA, ICW4_8086)
asm.io_wait()
asm.outb(PIC2_DATA, ICW4_8086)
asm.io_wait()
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
asm.io_wait()
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
asm.io_wait()
# 发送EOI信号
def eoi(irq: t.CUInt8T):
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
asm.outb(PIC1_COMMAND, OCW2_EOI)
# 检查是否是虚假中断(spurious interrupt)
# 返回 1 表示是虚假中断,0 表示是真实中断
def isSpurious(irq: t.CInt) -> t.CInt:
# 边界检查
if irq < 0 or irq > 15: return 0
isr: t.CUInt8T
if irq < 8:
# 发送OCW3,读取ISR(Interrupt Service Register)
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC1_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << irq))
else:
# 发送OCW3,读取从PIC的ISR
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC2_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << (irq - 8)))
# 设置IRQ屏蔽
def setMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) | (1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
# 清除IRQ屏蔽
def clearMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) & ~(1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
-26
View File
@@ -1,26 +0,0 @@
import asm
import t, c
PIT_CHANNEL0: t.CDefine = 0x40
PIT_CHANNEL1: t.CDefine = 0x41
PIT_CHANNEL2: t.CDefine = 0x42
PIT_COMMAND: t.CDefine = 0x43
def pit_init(frequency: t.CInt):
# 参数验证:确保频率为正数
if frequency <= 0: return
# 计算除数,使用16位无符号整数
divisor: t.CUInt32T = 1193180 / frequency
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
asm.outb(PIT_COMMAND, 0x36)
asm.io_wait()
# 写入低字节
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
asm.io_wait()
# 写入高字节
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
asm.io_wait()
-97
View File
@@ -1,97 +0,0 @@
from stdint import *
import t, c
import asm
RTC_CMOS_ADDR: t.CUInt16T = 0x70
RTC_CMOS_DATA: t.CUInt16T = 0x71
RTC_REG_SECONDS: t.CDefine = 0x00
RTC_REG_MINUTES: t.CDefine = 0x02
RTC_REG_HOURS: t.CDefine = 0x04
RTC_REG_DAY: t.CDefine = 0x07
RTC_REG_MONTH: t.CDefine = 0x08
RTC_REG_YEAR: t.CDefine = 0x09
RTC_REG_STATUS_A: t.CDefine = 0x0A
RTC_REG_STATUS_B: t.CDefine = 0x0B
RTC_TZ_OFFSET: t.CDefine = 8
rtc_seconds: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_minutes: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_hours: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_day: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_month: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_year: t.CStatic | t.CVolatile | t.CUInt16T = 0
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 rtc_read_time():
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
sec: t.CUInt8T = cmos_read(RTC_REG_SECONDS)
min_: t.CUInt8T = cmos_read(RTC_REG_MINUTES)
hour: t.CUInt8T = cmos_read(RTC_REG_HOURS)
day: t.CUInt8T = cmos_read(RTC_REG_DAY)
mon: t.CUInt8T = cmos_read(RTC_REG_MONTH)
year: t.CUInt8T = cmos_read(RTC_REG_YEAR)
reg_b: t.CUInt8T = cmos_read(RTC_REG_STATUS_B)
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)
if not (reg_b & 0x02) and (hour & 0x80):
hour = ((hour & 0x7F) + 12) % 24
hour = hour + RTC_TZ_OFFSET
if hour >= 24:
hour = hour - 24
day = day + 1
max_day: t.CUInt8T = 31
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
max_day = 30
elif mon == 2:
max_day = 28
y4: t.CUInt16T = t.CUInt16T(year) + 2000
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
max_day = 29
if day > max_day:
day = 1
mon = mon + 1
if mon > 12:
mon = 1
year = year + 1
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
rtc_seconds = sec
rtc_minutes = min_
rtc_hours = hour
rtc_day = day
rtc_month = mon
rtc_year = t.CUInt16T(year) + 2000
def rtc_init():
rtc_read_time()
def rtc_get_hours() -> t.CUInt8T:
return rtc_hours
def rtc_get_minutes() -> t.CUInt8T:
return rtc_minutes
def rtc_get_seconds() -> t.CUInt8T:
return rtc_seconds
def rtc_get_day() -> t.CUInt8T:
return rtc_day
def rtc_get_month() -> t.CUInt8T:
return rtc_month
def rtc_get_year() -> t.CUInt16T:
return rtc_year
-102
View File
@@ -1,102 +0,0 @@
import platform.pch.pic as pic
import platform.pch.pit as pit
import sched.sched as sched
import asm
import t, c
TIMER_FREQUENCY: t.CDefine = 1000
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
ticks: t.CStatic | t.CVolatile | t.CUInt64T = 0
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
timer_running: t.CStatic | t.CVolatile | bool = False
def timer_init():
global ticks, seconds, milliseconds, timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
pit.pit_init(TIMER_FREQUENCY)
def timer_handler():
global ticks, seconds, milliseconds, timer_running
if not timer_running:
pic.eoi(0)
return
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = ticks + 1
milliseconds = milliseconds + MILLISECONDS_PER_TICK
if milliseconds >= 1000:
seconds = seconds + 1
milliseconds = milliseconds - 1000
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
sched.Scheduler.sched_tick()
pic.eoi(0)
def timer_start():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_stop():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = False
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_reset():
global ticks, seconds, milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_get_ticks() -> t.CUInt64T:
current_ticks: t.CUInt64T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_ticks = ticks
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_ticks
def timer_get_seconds() -> t.CUInt32T:
current_seconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_seconds = seconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_seconds
def timer_get_milliseconds() -> t.CUInt32T:
current_milliseconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_milliseconds = milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_milliseconds
def timer_get_time(out_seconds: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | t.CPtr):
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
if out_seconds:
c.Set(c.Deref(out_seconds), seconds)
if out_milliseconds:
c.Set(c.Deref(out_milliseconds), milliseconds)
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_msleep(ms: t.CUInt32T):
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
def timer_sleep(sec: t.CUInt32T):
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
-202
View File
@@ -1,202 +0,0 @@
import mm
import drivers.serial.uart.serial as serial
import asm
import t, c
CORO_READY: t.CDefine = 0
CORO_RUNNING: t.CDefine = 1
CORO_YIELDED: t.CDefine = 2
CORO_DONE: t.CDefine = 3
MAX_COROUTINES: t.CDefine = 32
CORO_STACK_SIZE: t.CDefine = 8192
@t.Object
class Coroutine:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
cid: t.CInt
caller_rsp: t.CUInt64T
ret_val: t.CInt
def resume(self) -> t.CInt:
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if self.state == CORO_DONE: return self.ret_val
if self.state != CORO_READY and self.state != CORO_YIELDED: return -1
prev_cid: t.CInt = m.current_cid
m.current_cid = self.cid
self.state = CORO_RUNNING
_coro_old_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_new_rsp = c.Addr(self.rsp)
self.caller_rsp = t.CUInt64T(_coro_old_rsp)
_coro_switch()
if self.state == CORO_DONE:
return self.ret_val
return 0
@staticmethod
def _yield():
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
cid: t.CInt = m.current_cid
if cid < 0: return
m.coroutines[cid].state = CORO_YIELDED
prev_cid: t.CInt = -1
i: t.CInt
for i in range(m.count):
if m.coroutines[i].state == CORO_RUNNING and m.coroutines[i].caller_rsp != 0:
prev_cid = i
break
if prev_cid < 0: return
m.current_cid = prev_cid
_coro_old_rsp = c.Addr(m.coroutines[cid].rsp)
_coro_new_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_switch()
@property
def is_done(self) -> t.CInt:
if self.state == CORO_DONE:
return 1
return 0
@property
def is_yielded(self) -> t.CInt:
if self.state == CORO_YIELDED:
return 1
return 0
@property
def retval(self) -> t.CInt:
return self.ret_val
@t.Object
class CoroutineManager:
coroutines: t.CArray[Coroutine, MAX_COROUTINES]
current_cid: t.CInt
count: t.CInt
def __init__():
global _coro_mgr_ptr
_coro_mgr_ptr = c.Addr(_coro_mgr)
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
m.current_cid = 0
m.count = 1
m.coroutines[0].state = CORO_RUNNING
m.coroutines[0].cid = 0
m.coroutines[0].caller_rsp = 0
m.coroutines[0].ret_val = 0
m.coroutines[0].rsp = 0
m.coroutines[0].stack = None
m.coroutines[0].stack_size = 0
m.coroutines[0].func = None
m.coroutines[0].arg = None
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(m.coroutines[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def current() -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
return c.Addr(m.coroutines[m.current_cid])
@staticmethod
def get_coroutine(cid: t.CInt) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if cid < 0 or cid >= m.count: return None
return c.Addr(m.coroutines[cid])
@staticmethod
def create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if m.count >= MAX_COROUTINES: return None
cid: t.CInt = m.count
m.count += 1
co: Coroutine | t.CPtr = c.Addr(m.coroutines[cid])
co.state = CORO_READY
co.cid = cid
co.func = func
co.arg = arg
co.caller_rsp = 0
co.ret_val = 0
stack_ptr: t.CVoid | t.CPtr = mm.malloc(CORO_STACK_SIZE)
if not stack_ptr: return None
co.stack = stack_ptr
co.stack_size = CORO_STACK_SIZE
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + CORO_STACK_SIZE - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_coro_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {c.AsmInp(entry_addr, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 56
co.rsp = stack_top
return co
_coro_mgr: CoroutineManager = CoroutineManager()
_coro_mgr_ptr: CoroutineManager | t.CPtr = c.Addr(_coro_mgr)
_coro_old_rsp: t.CVoid | t.CPtr
_coro_new_rsp: t.CVoid | t.CPtr
@c.Attribute(t.attr.naked)
def _coro_switch():
c.Asm(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
mov rax, qword ptr [rip + _coro_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _coro_new_rsp]
mov rsp, qword ptr [rax]
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@c.Attribute(t.attr.naked)
def _coro_entry():
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
movsxd rcx, ecx
shl rcx, 5
mov rdi, qword ptr [rax + rcx + 24]
mov rax, qword ptr [rax + rcx + 16]
call rax
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
movsxd rcx, ecx
shl rcx, 5
mov dword ptr [rax + rcx + 32], 3
mov dword ptr [rax + rcx + 48], eax
add rsp, 8""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
Coroutine._yield()
while True:
asm.sti()
asm.hlt()
-277
View File
@@ -1,277 +0,0 @@
import mm
import mm.mm as mm_mm
import paging.paging as paging
import drivers.serial.uart.serial as serial
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import drivers.core.cpu.cpu as cpu
import intr.gdt as gdt
import viperlib
import string
import t, c
PROC_READY: t.CDefine = 0
PROC_RUNNING: t.CDefine = 1
PROC_BLOCKED: t.CDefine = 2
PROC_DONE: t.CDefine = 3
MAX_PROCESSES: t.CDefine = 8
MAX_PROC_THREADS: t.CDefine = 8
PROC_MAX_FDS: t.CDefine = 16
PROC_MAX_DIRS: t.CDefine = 8
KERN_STACK_SIZE: t.CDefine = 8192
USER_STACK_SIZE: t.CDefine = 65536
@t.Object
class Process:
pid: t.CInt
pml4_root: t.CUInt64T
threads: t.CArray[t.CInt, 8]
thread_count: t.CInt
state: t.CInt
entry: t.CVoid | t.CPtr
elf_base: t.CUInt64T
heap_start: t.CUInt64T
heap_size: t.CUInt64T
name: t.CArray[t.CChar, 32]
fd_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_FDS]
fd_used: t.CArray[t.CUInt8T, PROC_MAX_FDS]
dir_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_DIRS]
dir_used: t.CArray[t.CUInt8T, PROC_MAX_DIRS]
dir_pool: t.CArray[fat32_types.dirobj, PROC_MAX_DIRS]
kern_stack: t.CUInt64T
user_stack: t.CUInt64T
def addThread(self, tid: t.CInt) -> t.CInt:
if self.thread_count >= MAX_PROC_THREADS: return -1
self.threads[self.thread_count] = tid
self.thread_count += 1
return 0
def exit(self):
self.state = PROC_DONE
for i in range(PROC_MAX_FDS):
if self.fd_used[i]:
fp: t.CVoid | t.CPtr = self.fd_table[i]
if fp:
fat32.close(fp)
self.fd_used[i] = 0
self.fd_table[i] = t.CVoid(0, t.CPtr)
for i in range(PROC_MAX_DIRS):
if self.dir_used[i]:
dp: t.CVoid | t.CPtr = self.dir_table[i]
if dp:
fat32.closedir(dp)
self.dir_used[i] = 0
self.dir_table[i] = t.CVoid(0, t.CPtr)
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if m.current_pid == self.pid:
m.current_pid = 0
m.processes[0].state = PROC_RUNNING
if self.pml4_root != 0:
kernel_cr3: t.CUInt64T = m.processes[0].pml4_root
if kernel_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(kernel_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(kernel_cr3)
@property
def is_running(self) -> t.CInt:
if self.state == PROC_RUNNING:
return 1
return 0
@property
def is_done(self) -> t.CInt:
if self.state == PROC_DONE:
return 1
return 0
@t.Object
class ProcessManager:
processes: t.CArray[Process, MAX_PROCESSES]
current_pid: t.CInt
count: t.CInt
def __init__(self):
global _proc_mgr_ptr
_proc_mgr_ptr = c.Addr(_proc_mgr)
m: ProcessManager | t.CPtr = _proc_mgr_ptr
m.current_pid = 0
m.count = 1
p: Process | t.CPtr = c.Addr(m.processes[0])
p.pid = 0
p.state = PROC_RUNNING
p.thread_count = 0
p.pml4_root = 0
p.entry = None
p.elf_base = 0
p.heap_start = 0
p.heap_size = 0
name_str: str = "kernel"
i: t.CInt = 0
for ch in name_str:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
p.fd_used[j] = 0
p.fd_table[j] = t.CVoid(0, t.CPtr)
for j in range(PROC_MAX_DIRS):
p.dir_used[j] = 0
p.dir_table[j] = t.CVoid(0, t.CPtr)
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _switch(pid: t.CInt) -> t.CInt:
global _saved_cr3
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return -1
p: Process | t.CPtr = c.Addr(m.processes[pid])
if p.state == PROC_DONE: return -1
old_pid: t.CInt = m.current_pid
if old_pid == pid: return 0
if old_pid >= 0 and old_pid < m.count:
m.processes[old_pid].state = PROC_READY
p.state = PROC_RUNNING
m.current_pid = pid
c.Asm(f"""mov {c.AsmOut(_saved_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3
mov rax, {c.AsmInp(p.pml4_root, t.ASM_DESCR.REG_ANY)}
mov cr3, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return 0
@staticmethod
def current() -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
return c.Addr(m.processes[m.current_pid])
@staticmethod
def get_process(pid: t.CInt) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return None
return c.Addr(m.processes[pid])
@staticmethod
def create_process(name: str, entry: t.CVoid | t.CPtr) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
_dbp: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dbp), 80, "[process] create_process count=%d MAX=%d\n", m.count, MAX_PROCESSES)
serial.puts(_dbp)
if m.count >= MAX_PROCESSES: return None
pid: t.CInt = m.count
m.count += 1
p: Process | t.CPtr = c.Addr(m.processes[pid])
p.pid = pid
p.state = PROC_READY
p.entry = entry
p.elf_base = 0
p.thread_count = 0
p.heap_start = 0
p.heap_size = 0
string.memset(c.Addr(p.name), 0, 32)
i: t.CInt = 0
for ch in name:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
p.fd_used[j] = 0
p.fd_table[j] = t.CVoid(0, t.CPtr)
for j in range(PROC_MAX_DIRS):
p.dir_used[j] = 0
p.dir_table[j] = t.CVoid(0, t.CPtr)
ks: t.CVoid | t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
if ks is None:
serial.puts("[process] kernel stack alloc failed\n")
m.count = m.count - 1
return None
ks_size: t.CUInt64T = KERN_STACK_SIZE
p.kern_stack = t.CUInt64T(ks) + ks_size
us: t.CVoid | t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
if us is None:
serial.puts("[process] user stack alloc failed\n")
mm_mm.free(ks)
m.count = m.count - 1
return None
us_size: t.CUInt64T = USER_STACK_SIZE
p.user_stack = t.CUInt64T(us) + us_size
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return p
_proc_mgr: ProcessManager = ProcessManager()
_proc_mgr_ptr: ProcessManager | t.CPtr = c.Addr(_proc_mgr)
_saved_cr3: t.CUInt64T
def current() -> t.CInt:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
return m.current_pid
def switch_pid(new_pid: t.CInt):
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if m.current_pid == new_pid: return
if m.current_pid >= 0 and m.current_pid < m.count:
old_p: Process | t.CPtr = c.Addr(m.processes[m.current_pid])
if old_p.state != PROC_DONE:
old_p.state = PROC_READY
if new_pid >= 0 and new_pid < m.count:
new_p: Process | t.CPtr = c.Addr(m.processes[new_pid])
new_p.state = PROC_RUNNING
new_cr3: t.CUInt64T = new_p.pml4_root
if new_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(new_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(new_cr3)
# Update TSS RSP0 and GS kernel_rsp0 for the new process
# This is needed so interrupts from Ring 3 use the correct kernel stack
if new_p.kern_stack != 0:
gdt.set_tss_rsp0(new_p.kern_stack)
cpu.set_kernel_rsp0(new_p.kern_stack)
m.current_pid = new_pid
def get_pid(tid: t.CInt) -> t.CInt:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
i: t.CInt
for i in range(m.count):
p: Process | t.CPtr = c.Addr(m.processes[i])
j: t.CInt
for j in range(p.thread_count):
if p.threads[j] == tid:
return p.pid
return -1
def drop_to_user_mode(entry: t.CVoid | t.CPtr, user_rsp: t.CUInt64T, kern_rsp: t.CUInt64T):
# NOTE: Do NOT swapgs here. This OS uses reverse GS convention:
# GS_BASE = 0 (kernel & user), KERNEL_GS_BASE = &_per_cpu
# syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu
# syscall/ISR return does swapgs to restore GS_BASE = 0
# GS state is restored in isrCommonhandler before _yield() if needed.
c.Asm(f"""cli
mov rsp, {c.AsmInp(kern_rsp, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(user_rsp, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}
mov r11, 0x202
push 0x23
push rdx
push r11
push 0x1B
push rcx
iretq""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R11, 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_RBP])
-299
View File
@@ -1,299 +0,0 @@
import mm
import asm
import sched.process as proc
import drivers.serial.uart.serial as serial
import viperlib
import t, c
THREAD_READY: t.CDefine = 0
THREAD_RUNNING: t.CDefine = 1
THREAD_BLOCKED: t.CDefine = 2
THREAD_DONE: t.CDefine = 3
MAX_THREADS: t.CDefine = 16
THREAD_STACK_SIZE: t.CDefine = 65536
SCHED_QUANTUM: t.CDefine = 10
_yield_cnt: t.CUInt32T = 0
_yield_lock: t.CInt = 0
@t.Object
class Thread:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
tid: int
pid: t.CInt
def block(self):
self.state = THREAD_BLOCKED
Scheduler._yield()
def unblock(self):
if self.state == THREAD_BLOCKED:
self.state = THREAD_READY
@property
def is_running(self) -> t.CInt:
if self.state == THREAD_RUNNING:
return 1
return 0
@property
def is_blocked(self) -> t.CInt:
if self.state == THREAD_BLOCKED:
return 1
return 0
@property
def is_done(self) -> t.CInt:
if self.state == THREAD_DONE:
return 1
return 0
@t.Object
class Scheduler:
threads: t.CArray[Thread, MAX_THREADS]
current_tid: t.CInt
thread_count: t.CInt
enabled: t.CInt
needs_reschedule: t.CInt
tick_count: t.CInt
def __init__(self):
global _sched_ptr
_sched_ptr = c.Addr(_sched_storage)
s: Scheduler | t.CPtr = _sched_ptr
s.current_tid = 0
s.thread_count = 1
s.enabled = 0
s.needs_reschedule = 0
s.tick_count = 0
i: int
for i in range(MAX_THREADS):
s.threads[i].rsp = 0
s.threads[i].stack = None
s.threads[i].stack_size = 0
s.threads[i].func = None
s.threads[i].arg = None
s.threads[i].state = THREAD_DONE
s.threads[i].tid = i
s.threads[i].pid = 0
s.enabled = 1
s.threads[0].state = THREAD_RUNNING
s.threads[0].tid = 0
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(s.threads[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _yield():
global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock
_if_saved: t.CInt = 0
c.Asm(f"""pushfq
pop rax
shr rax, 9
and eax, 1
mov {c.AsmOut(_if_saved, t.ASM_DESCR.OUTPUT_REG)}, eax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
asm.cli()
if _yield_lock:
if _if_saved:
asm.sti()
return
_yield_lock = 1
s: Scheduler | t.CPtr = _sched_ptr
s.needs_reschedule = 0
s.tick_count = 0
old_tid: t.CInt = s.current_tid
next_tid: t.CInt = old_tid + 1
if next_tid >= s.thread_count:
next_tid = 0
found: t.CInt = 0
count: t.CInt = 0
while count < s.thread_count:
st: t.CInt = s.threads[next_tid].state
if st == THREAD_READY or st == THREAD_RUNNING:
found = 1
break
next_tid += 1
if next_tid >= s.thread_count:
next_tid = 0
count += 1
if found == 0:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if next_tid == old_tid:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if s.threads[old_tid].state == THREAD_RUNNING:
s.threads[old_tid].state = THREAD_READY
s.threads[next_tid].state = THREAD_RUNNING
_switch_old_rsp = c.Addr(s.threads[old_tid].rsp)
_switch_new_rsp = c.Addr(s.threads[next_tid].rsp)
s.current_tid = next_tid
next_pid: t.CInt = s.threads[next_tid].pid
_yield_cnt += 1
proc.switch_pid(next_pid)
_yield_lock = 0
_do_switch()
if _if_saved:
asm.sti()
@staticmethod
def sched_tick():
s: Scheduler | t.CPtr = _sched_ptr
if not s.enabled: return
if s.thread_count <= 1: return
s.tick_count += 1
if s.tick_count >= SCHED_QUANTUM:
s.tick_count = 0
s.needs_reschedule = 1
@staticmethod
def try_reschedule():
s: Scheduler | t.CPtr = _sched_ptr
if s.needs_reschedule:
s.needs_reschedule = 0
Scheduler._yield()
@staticmethod
def disable():
s: Scheduler | t.CPtr = _sched_ptr
s.enabled = 0
@staticmethod
def enable():
s: Scheduler | t.CPtr = _sched_ptr
s.enabled = 1
@staticmethod
def current() -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
return c.Addr(s.threads[s.current_tid])
@staticmethod
def get_thread(tid: t.CInt) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if tid < 0 or tid >= s.thread_count: return None
return c.Addr(s.threads[tid])
@staticmethod
def create_thread(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr, thread_pid: t.CInt = 0) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if s.thread_count >= MAX_THREADS: return None
tid: int = s.thread_count
s.thread_count += 1
th: Thread | t.CPtr = c.Addr(s.threads[tid])
th.state = THREAD_READY
th.tid = tid
th.pid = thread_pid
th.func = func
th.arg = arg
stack_size: t.CUInt64T = THREAD_STACK_SIZE
stack_ptr: t.CVoid | t.CPtr = mm.malloc(stack_size)
if not stack_ptr: return None
th.stack = stack_ptr
th.stack_size = stack_size
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + stack_size - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_thread_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 64], 0x202
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {c.AsmInp(entry_addr, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 64
th.rsp = stack_top
return th
_sched_storage: Scheduler = Scheduler()
_sched_ptr: Scheduler | t.CPtr = c.Addr(_sched_storage)
_switch_old_rsp: t.CVoid | t.CPtr
_switch_new_rsp: t.CVoid | t.CPtr
@c.Attribute(t.attr.naked)
def _do_switch():
c.Asm(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
pushfq
mov rax, qword ptr [rip + _switch_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _switch_new_rsp]
mov rsp, qword ptr [rax]
popfq
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@c.Attribute(t.attr.naked)
def _thread_entry():
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov rdi, qword ptr [rax + rcx + 32]
mov rax, qword ptr [rax + rcx + 24]
call rax
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov dword ptr [rax + rcx + 40], 3
add rsp, 8""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, 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])
Scheduler._yield()
while True:
asm.sti()
asm.hlt()
Scheduler._yield()
def thread_current() -> t.CInt:
s: Scheduler | t.CPtr = _sched_ptr
return s.current_tid
def needs_reschedule() -> t.CInt:
s: Scheduler | t.CPtr = _sched_ptr
return s.needs_reschedule
def sched_dump():
s: Scheduler | t.CPtr = _sched_ptr
dl: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(dl), 80, "[sched] dump: cur=%d cnt=%d yields=%u\n", s.current_tid, s.thread_count, _yield_cnt)
serial.puts(dl)
for i in range(s.thread_count):
sl: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(sl), 80, " t%d: st=%d pid=%d rsp=0x%lx\n", i, s.threads[i].state, s.threads[i].pid, s.threads[i].rsp)
serial.puts(sl)
File diff suppressed because it is too large. Load diff
-50
View File
@@ -1,50 +0,0 @@
import t, c
import drivers.input.keyboard.keyboard as keyboard
import drivers.usb.hid.usb_kbd as usb_kbd
import drivers.serial.uart.serial as serial
import sched.sched as sched
import viperlib
SERVICE_KEYBOARD: t.CDefine = 1
@t.Object
class KeyboardService:
th: sched.Thread | t.CPtr
running: t.CInt
usb_kbd_th: sched.Thread | t.CPtr
def __init__(self):
self.th = None
self.running = 0
self.usb_kbd_th = None
kbd_svc: KeyboardService
def kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
serial.puts("[kbd_svc] started\n")
while True:
if keyboard.has_data():
sc: t.CUInt8T = keyboard.read_scancode()
else:
sched.Scheduler._yield()
return 0
def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
serial.puts("[usb_kbd_svc] started\n")
evt: usb_kbd.usb_kbd_event
while True:
if usb_kbd.has_data():
usb_kbd.read_event(c.Addr(evt))
else:
sched.Scheduler._yield()
return 0
def start() -> t.CInt:
global kbd_svc
kbd_svc = KeyboardService()
keyboard.init()
serial.puts("[kbd_svc] PS/2 keyboard initialized, IRQ1 installed\n")
usb_kbd.init()
kbd_svc.running = 1
return 0
-13
View File
@@ -1,13 +0,0 @@
import t, c
import drivers.input.mouse.mouse as mouse
import drivers.usb.hid.usb_mouse as usb_mouse
import drivers.serial.uart.serial as serial
import sched.sched as sched
SERVICE_MOUSE: t.CDefine = 2
def start() -> t.CInt:
serial.puts("[mse_svc] mouse initialized\n")
if usb_mouse.init() == 0:
serial.puts("[mse_svc] usb mouse initialized\n")
return 0
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

+57
View File
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="2048" height="2048">
<path d="M0 0 C1.43859375 -0.00386719 1.43859375 -0.00386719 2.90625 -0.0078125 C5.5 0.125 5.5 0.125 8.5 1.125 C10.07494679 1.21669387 11.65351919 1.25137572 13.23113275 1.25215852 C14.21223816 1.25507056 15.19334358 1.25798259 16.20417947 1.26098287 C17.82819537 1.25816256 17.82819537 1.25816256 19.48501968 1.25528526 C20.63616652 1.25722869 21.78731336 1.25917212 22.97334343 1.26117444 C26.18790327 1.26559368 29.40242792 1.26551071 32.61698911 1.26360132 C36.10693665 1.26263044 39.59687675 1.26745584 43.08682132 1.27158034 C49.20990348 1.27802579 55.33297881 1.2807976 61.45606422 1.28120613 C70.56131082 1.28184984 79.66654691 1.28823542 88.77178995 1.29595293 C103.14813112 1.30804145 117.52447181 1.31669674 131.90081661 1.32299107 C154.72058471 1.33301518 177.54033782 1.35226383 200.36009693 1.37453346 C209.13518953 1.38306462 217.91028239 1.39133059 226.68537521 1.39963722 C227.66035547 1.40056223 228.63533572 1.40148724 229.63986083 1.40244028 C252.85870126 1.42444049 276.07754337 1.44422712 299.29638672 1.46289062 C300.31261062 1.4637103 301.32883452 1.46452998 302.37585309 1.4653745 C326.08672853 1.48446028 349.79760389 1.50142152 373.50848389 1.51373291 C374.52825771 1.51426258 375.54803154 1.51479225 376.5987076 1.51533796 C384.81851069 1.51958956 393.03831381 1.52376588 401.25811695 1.52792276 C435.12980914 1.54511112 469.00148086 1.57231006 502.87315546 1.61108314 C507.65434625 1.61654521 512.43553718 1.62187815 517.21672821 1.62712479 C518.62824923 1.62867636 518.62824923 1.62867636 520.06828583 1.63025927 C535.22952948 1.64660069 550.39075882 1.65211397 565.55201044 1.65342245 C580.78324492 1.65492508 596.01444047 1.6670549 611.24565777 1.69017886 C620.30022251 1.70358381 629.35470229 1.70856296 638.40927478 1.7016325 C644.45363612 1.69782031 650.497922 1.7048069 656.54226363 1.72064828 C659.98877247 1.72936664 663.4351068 1.73330374 666.88161829 1.72407441 C670.59179392 1.71663549 674.30147582 1.72747849 678.01161575 1.74303246 C679.08492836 1.73646991 680.15824097 1.72990737 681.2640782 1.72314596 C687.16414252 1.77028764 691.25210961 2.40563744 696.5 5.125 C699.01036535 5.9108535 701.53016035 6.59954783 704.0703125 7.28125 C706.5 8.125 706.5 8.125 708.81640625 9.55078125 C712.15660838 11.51017202 715.65183927 12.6206182 719.3125 13.8125 C725.12314078 15.78005859 730.57365124 18.01662951 736 20.875 C743.91548995 25.03164703 752.13060775 28.29606801 760.45703125 31.53613281 C767.24833937 34.18465636 773.88894678 37.05565422 780.5 40.125 C781.62792969 40.62644531 782.75585938 41.12789063 783.91796875 41.64453125 C789.87544004 44.42580487 794.18929719 47.33005411 798.62890625 52.17578125 C801.08514877 54.73458087 803.83225627 56.69473172 806.69921875 58.765625 C809.20702548 60.65871988 811.3078776 62.87807454 813.5 65.125 C815.44546571 66.87634115 817.41886327 68.59202216 819.3984375 70.3046875 C820.76539079 71.48870281 822.12521267 72.68101917 823.4765625 73.8828125 C827.55869277 77.50956569 831.7547855 80.91687025 836.08203125 84.24609375 C843.81041205 90.25150759 851.22731444 96.579583 858.5 103.125 C862.79301203 106.96166823 867.14571406 110.64678818 871.6875 114.1875 C875.54211521 117.23464994 878.45427389 120.29608718 881.5 124.125 C883.69250727 126.02122251 885.95622437 127.73591916 888.3125 129.421875 C892.8061002 132.68675639 896.64337693 136.21058322 900.5078125 140.1953125 C902.37665424 142.00552391 904.25777473 143.49498445 906.375 145 C909.75743286 147.42739299 912.59207175 150.14592977 915.5 153.125 C918.98022329 156.68492306 922.46095715 159.74889797 926.50390625 162.63671875 C930.39058911 165.53461732 933.90514203 168.87823568 937.5 172.125 C938.83079361 173.29456285 940.1640428 174.46133886 941.5 175.625 C945.11855573 178.78405659 948.70954679 181.97304518 952.29296875 185.171875 C953.66010228 186.38172768 955.03611085 187.5817273 956.42578125 188.765625 C960.74873375 192.45311243 964.90660118 196.31083127 969 200.25 C969.54116455 200.75305664 970.0823291 201.25611328 970.63989258 201.77441406 C972.99660725 204.07990406 974.40476361 205.5678671 974.96875 208.8671875 C974.5 211.125 974.5 211.125 972.5 213.125 C970.61562687 213.85104698 968.70207313 214.50219769 966.77734375 215.11328125 C965.60856689 215.48694824 964.43979004 215.86061523 963.2355957 216.24560547 C961.98222412 216.63893066 960.72885254 217.03225586 959.4375 217.4375 C958.1381504 217.85006252 956.83891587 218.26298758 955.53979492 218.67626953 C948.5355565 220.89675968 941.51300334 223.022592 934.44506836 225.03051758 C925.80854358 227.53971466 917.31020977 230.50140017 908.78790283 233.3694458 C900.95847523 236.00276091 893.1395024 238.63053102 885.1875 240.875 C878.27824501 242.83179209 871.55683625 245.19016733 864.79760742 247.61035156 C859.89923627 249.34437211 855.03775758 250.85190074 850 252.125 C834.43818465 256.15515457 821.00057835 260.7909593 808.5 271.125 C807.82066406 271.68316406 807.14132812 272.24132812 806.44140625 272.81640625 C805.34654654 273.74438203 804.26232429 274.68511918 803.19140625 275Line truncated
<path d="M0 0 C1.87410553 -0.02882263 1.87410553 -0.02882263 3.78607178 -0.05822754 C5.15066794 -0.06793431 6.51527271 -0.0764893 7.87988281 -0.08398438 C8.57336067 -0.08963913 9.26683853 -0.09529388 9.98133087 -0.10112 C13.66318779 -0.13109726 17.34488861 -0.14955102 21.02685547 -0.15820312 C24.04330478 -0.16692515 27.05859457 -0.19451452 30.07470703 -0.24023438 C62.05878142 -0.71603308 62.05878142 -0.71603308 74.83300781 6.32226562 C76.23824707 7.05388916 76.23824707 7.05388916 77.671875 7.80029297 C84.94627824 11.73996458 91.37540913 17.1855858 97.83300781 22.32226562 C99.16912109 23.381875 99.16912109 23.381875 100.53222656 24.46289062 C102.97193019 26.40852554 105.40246586 28.36520587 107.83300781 30.32226562 C108.68894531 31.00289062 109.54488281 31.68351563 110.42675781 32.38476562 C114.07474911 35.28557799 117.70690062 38.18252129 121.20800781 41.25976562 C124.22123139 43.87688469 127.37956066 46.25482674 130.58300781 48.63476562 C139.60741948 55.34377755 148.26891224 62.50597841 156.68457031 69.96289062 C161.16621103 73.92673221 165.76834253 77.69602372 170.45410156 81.41601562 C173.06943739 83.51171987 175.62630974 85.66038343 178.15332031 87.86132812 C179.26285929 88.826369 180.38259248 89.77982681 181.51269531 90.72070312 C203.40427145 109.22988982 203.40427145 109.22988982 207.83300781 121.32226562 C208.66275 123.30294052 209.49627508 125.28203372 210.33300781 127.25976562 C210.95755859 128.7834375 210.95755859 128.7834375 211.59472656 130.33789062 C214.15847576 136.51676882 217.00177331 142.56655147 219.85644531 148.61523438 C220.21311279 149.37102783 220.56978027 150.12682129 220.93725586 150.90551758 C221.64534326 152.40356049 222.355073 153.9008285 223.06665039 155.3972168 C227.83300781 165.4610834 227.83300781 165.4610834 227.83300781 170.32226562 C228.49300781 170.32226562 229.15300781 170.32226562 229.83300781 170.32226562 C230.22488281 171.41539062 230.61675781 172.50851562 231.02050781 173.63476562 C232.27815493 177.00030017 233.69377481 180.25201513 235.20800781 183.50976562 C237.60158636 188.67069475 239.60270713 193.9264454 241.52441406 199.27929688 C242.75369103 202.39742165 242.75369103 202.39742165 244.77832031 205.20898438 C247.13673802 208.7824804 248.60778549 212.34747542 250.14550781 216.32226562 C252.28246549 221.68767498 254.54076046 226.87949172 257.20800781 232.00976562 C260.84932475 239.07820438 263.80178067 246.38143656 266.72509766 253.7722168 C268.49135184 258.20522266 270.302487 262.26333909 272.83300781 266.32226562 C273.60406487 268.1804314 274.32999022 270.05769041 275.02050781 271.94726562 C279.63140189 284.18280082 284.607226 296.26409502 290.59863281 307.89257812 C292.16373794 310.97325973 293.47925323 314.1438853 294.83300781 317.32226562 C295.61745301 318.88840358 296.40987243 320.45055997 297.20800781 322.00976562 C299.58916087 326.70790894 301.59351132 331.51049921 303.58300781 336.38476562 C304.73625522 339.09489704 305.98949153 341.70240887 307.33300781 344.32226562 C310.16255909 349.85757531 312.49369373 355.56622466 314.83300781 361.32226562 C317.99874712 369.05833847 321.32809375 376.7069447 324.75024414 384.33203125 C327.05552171 389.49585301 329.22450609 394.70052878 331.33300781 399.94726562 C334.21213545 407.08170247 337.53898567 413.92075478 341.03222656 420.77148438 C346.83300781 432.20946736 346.83300781 432.20946736 346.83300781 436.32226562 C347.49300781 436.32226562 348.15300781 436.32226562 348.83300781 436.32226562 C349.1359375 437.1446875 349.43886719 437.96710938 349.75097656 438.81445312 C351.73651914 444.10516043 353.72451414 449.30402066 356.33300781 454.32226562 C358.82082889 459.11909563 360.69649102 464.06501504 362.59472656 469.11914062 C364.05383396 472.89348783 365.69874287 476.54824977 367.40332031 480.21679688 C368.48238788 482.56067314 369.53787919 484.90920718 370.57519531 487.27148438 C374.24836792 495.63261176 378.04976242 503.91033614 382.02050781 512.13476562 C385.24537657 518.82085247 388.14633604 525.47021049 390.70410156 532.43945312 C392.26792911 536.4328951 394.22040473 540.18335657 396.18066406 543.99414062 C398.1034708 547.86702796 399.84895607 551.79971734 401.58300781 555.75976562 C404.56190043 562.55201713 407.68207529 569.26288869 410.89550781 575.94726562 C414.42834028 583.30627766 417.80799145 590.70768437 421.04394531 598.20117188 C423.15888208 603.09453129 425.33705032 607.95917119 427.52050781 612.82226562 C427.88926025 613.64734619 428.2580127 614.47242676 428.63793945 615.32250977 C430.34586501 619.12111197 432.09530728 622.88008087 433.98535156 626.59179688 C435.46163903 629.50950745 436.67072187 632.40284726 437.70800781 635.50976562 C440.00105327 641.98164295 442.88313053 648.12922132 445.83300781 654.32226562 C446.97919244 656.7373483 448.12466916 659.15276519 449.26977539 661.56835938 C450.04006522 663.19155487 450.81194045 664.81399932 451.58569336 666.43554688 C454.08878497 671.69420811 456.48593201 676.99234018 458.83300781 682.32226562 C461.99550894 689.41193233 465.23699803 696.44086054 468.83Line truncated
<path d="M0 0 C5.44333286 1.53093737 8.92825297 5.29018604 13 9 C14.35338261 10.14675931 15.70753684 11.29260864 17.0625 12.4375 C21.64462627 16.44686048 25.45821971 20.99400134 29.38046265 25.63258362 C34.2136011 31.25757669 39.38333733 36.48054236 44.66015625 41.6875 C46.04798169 43.06591387 47.43580107 44.4443339 48.82327175 45.82310486 C52.20679048 49.18389109 55.59581215 52.53911093 58.98754883 55.89160156 C60.90240519 57.78472355 62.81446848 59.68059109 64.72373962 61.5793457 C66.51027671 63.35563876 68.3008835 65.1278513 70.09620667 66.89526367 C74.35703946 71.1384933 78.20739247 75.38633314 81.71757507 80.269104 C83.45492247 82.61401137 85.42886308 84.62111363 87.5234375 86.6484375 C88.31621094 87.42574219 89.10898438 88.20304688 89.92578125 89.00390625 C90.73402344 89.78636719 91.54226563 90.56882812 92.375 91.375 C94.01229839 92.96152945 95.64536337 94.55244365 97.2734375 96.1484375 C97.98935059 96.84114746 98.70526367 97.53385742 99.44287109 98.24755859 C101 100 101 100 101 102 C97.76847648 100.57784217 95.59614267 98.85315081 93.1015625 96.3671875 C92.01101563 95.28050781 92.01101563 95.28050781 90.8984375 94.171875 C90.14820313 93.41390625 89.39796875 92.6559375 88.625 91.875 C87.8825 91.14023437 87.14 90.40546875 86.375 89.6484375 C85.64539062 88.91625 84.91578125 88.1840625 84.1640625 87.4296875 C83.50873535 86.77210449 82.8534082 86.11452148 82.17822266 85.43701172 C80.40676903 83.45509622 78.90545865 81.50615912 77.36254883 79.35375977 C73.42786725 74.03908037 68.74419397 69.53326462 64.03515625 64.91015625 C63.07341827 63.95725701 62.11228386 63.00374827 61.15171814 62.04966736 C57.61754348 58.54196208 54.07249327 55.04531716 50.52764893 51.54840088 C47.52256879 48.58311201 44.5218497 45.61353187 41.52651787 42.63839531 C40.1377354 41.26236732 38.74278986 39.89256827 37.34767151 38.52296448 C32.68049146 33.8915949 28.39133942 29.20890356 24.46846008 23.92750549 C22.24689754 21.01147525 19.73765741 18.43878566 17.125 15.875 C16.61469238 15.36783447 16.10438477 14.86066895 15.57861328 14.33813477 C11.86265546 10.70169682 7.96638614 7.44283837 3.7421875 4.40234375 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.99 0.495 0.99 0.495 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-10.22159357 9.88886962 -20.26620359 19.24636214 -28.94433594 29.45092773 C-33.33817211 34.48296797 -38.06905727 39.16680262 -42.81651497 43.8611145 C-44.44720722 45.47414979 -46.07410308 47.09093049 -47.70005798 48.70874023 C-52.31793061 53.30238803 -56.94152361 57.8902459 -61.56958008 62.47363281 C-64.41544977 65.29255287 -67.25629051 68.11646317 -70.09420586 70.94338989 C-71.16746948 72.0104976 -72.24261966 73.0757117 -73.31978035 74.1388855 C-78.51758323 79.26974787 -83.59728576 84.33132654 -87.79176331 90.34082031 C-89.85752511 93.1775741 -92.35567767 95.56967547 -94.875 98 C-95.37257813 98.48855469 -95.87015625 98.97710938 -96.3828125 99.48046875 C-97.58386954 100.65842854 -98.79123559 101.82995047 -100 103 C-100.66 102.67 -101.32 102.34 -102 102 C-97.66938005 96.88958996 -93.15590527 92.09370778 -88.30859375 87.46875 C-86.43361103 85.46369234 -84.90438774 83.5337759 -83.31016541 81.31732178 C-80.10058647 77.01114969 -76.52866446 73.23952404 -72.72875977 69.45410156 C-72.027117 68.74734787 -71.32547424 68.04059418 -70.60256958 67.31242371 C-68.30394979 65.00001179 -65.99808728 62.69499372 -63.69140625 60.390625 C-62.07985421 58.77518165 -60.46852455 57.15951643 -58.85740662 55.54364014 C-55.48930414 52.16809876 -52.11738238 48.79642904 -48.74291992 45.42724609 C-44.42597845 41.11611025 -40.12053683 36.79368847 -35.81810093 32.46808243 C-32.49728519 29.13251882 -29.16955123 25.80392492 -25.83979607 22.47728729 C-24.24948973 20.88646875 -22.66153521 19.29329543 -21.07602119 17.6977005 C-18.85800961 15.46731558 -16.6306167 13.2467285 -14.40063477 11.02832031 C-13.75262405 10.37266586 -13.10461334 9.71701141 -12.43696594 9.04148865 C-8.57529327 5.22384661 -4.92754094 2.33444496 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.625 5.34765625 -0.625 5.34765625 -3 8.0625 C-5.93698686 11.51830943 -8.75427783 14.94221196 -11.3125 18.6875 C-15.29868574 24.50145294 -19.54276155 30.1095513 -23.7890625 35.734375 C-25.9890044 38.64872406 -28.16907394 41.57660234 -30.3359375 44.515625 C-30.87645752 45.24571777 -31.41697754 45.97581055 -31.97387695 46.72802734 C-33.01261099 48.13184279 -34.04776171 49.53831861 -35.07885742 50.94775391 C-35.54912354 51.58116699 -36.01938965 52.21458008 -36.50390625 52.8671875 C-36.91455322 53.42519043 -37.3252002 53.98319336 -37.74829102 54.55810547 C-39 56 -39 56 -42 58 C-40.57903924 53.77531559 -38.50867165 50.93955733 -35.625 47.5625 C-32.48959794 43.82298385 -29.66696013 40.08933887 -27 36 C-24.70129936 32.97299816 -22.34483765 29.99133556 -20 27 C-16.45233144 22.43871185 -13.16862732 17.77161076 -10 12.9375 C-6.94299635 8.29908484 -3.73419762 4.10761738 0 0 Z " fill="#0DC260" transform="translate(1664,1109)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.34169662 5.05562693 -1.69564379 6.86486955 -3.25 8.75 C-4.18647751 9.92582536 -5.12131468 11.10295862 -6.0546875 12.28125 C-6.78703613 13.19970703 -6.78703613 13.19970703 -7.53417969 14.13671875 C-9.88398864 17.12368442 -12.1336178 20.18123735 -14.375 23.25 C-14.82472168 23.86528564 -15.27444336 24.48057129 -15.73779297 25.11450195 C-19.31788916 30.03099096 -22.85663624 34.97668341 -26.375 39.9375 C-26.86274902 40.62295898 -27.35049805 41.30841797 -27.85302734 42.01464844 C-31.07241726 46.57646529 -34.08918083 51.2356156 -37 56 C-37.33 55.34 -37.66 54.68 -38 54 C-36.55859375 51.2421875 -36.55859375 51.2421875 -34.4375 47.875 C-34.06689453 47.28533447 -33.69628906 46.69566895 -33.31445312 46.08813477 C-30.89736314 42.28455772 -28.3370912 38.65452968 -25.5703125 35.1015625 C-22.85128247 31.46266161 -20.41173412 27.63484565 -17.9296875 23.83203125 C-16.07017303 21.10298673 -14.086559 18.55771748 -12 16 C-11.03492127 14.73428156 -10.07612986 13.46373357 -9.125 12.1875 C-8.6196875 11.51074219 -8.114375 10.83398438 -7.59375 10.13671875 C-7.0678125 9.43160156 -6.541875 8.72648437 -6 8 C-4.87540898 6.49969335 -3.75042464 4.99968142 -2.625 3.5 C-2.12226562 2.8296875 -1.61953125 2.159375 -1.1015625 1.46875 C-0.73804688 0.9840625 -0.37453125 0.499375 0 0 Z " fill="#0DC260" transform="translate(1509,1315)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-11.17878346 10.5868994 -21.73310024 20.90322611 -31.1953125 31.97265625 C-34.61943288 35.81923304 -38.3225033 39.39755425 -42 43 C-42.66 42.34 -43.32 41.68 -44 41 C-38.86950975 35.79321757 -33.72711487 30.59841286 -28.57641602 25.41162109 C-26.82692975 23.64708236 -25.08014983 21.87985596 -23.33618164 20.10986328 C-20.82370575 17.5608501 -18.30153929 15.02177671 -15.77734375 12.484375 C-15.00414291 11.69569031 -14.23094208 10.90700562 -13.43431091 10.09442139 C-9.24303815 5.90186564 -5.4197086 2.47910486 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.19140625 1.328125 3.19140625 1.328125 4.5625 3.25 C5.09101562 3.97960938 5.61953125 4.70921875 6.1640625 5.4609375 C7.07285156 6.71777344 7.07285156 6.71777344 8 8 C9.47680111 9.96011784 10.95610817 11.91834936 12.4375 13.875 C18.89826433 22.51078117 24.95045701 31.36455683 30.875 40.375 C31.45926758 41.25607422 32.04353516 42.13714844 32.64550781 43.04492188 C33.19303711 43.88345703 33.74056641 44.72199219 34.3046875 45.5859375 C34.79952637 46.3392334 35.29436523 47.0925293 35.80419922 47.86865234 C36.96346212 49.93487634 37.55479394 51.68479735 38 54 C35.15497965 51.41843814 33.21663697 48.46505704 31.12109375 45.2578125 C30.36164909 44.10300467 29.60204015 42.94830486 28.84228516 41.79370117 C28.44906067 41.19351166 28.05583618 40.59332214 27.6506958 39.97494507 C21.70740437 30.91230022 15.74825198 21.92928068 8.9453125 13.48046875 C5.60068864 9.21573753 2.74542467 4.66722194 0 0 Z " fill="#0DC260" transform="translate(541,1321)"/>
<path d="M0 0 C0 3.95229679 -1.3349536 5.08305206 -3.75 8.1875 C-4.57984179 9.26530583 -5.40924597 10.34344869 -6.23828125 11.421875 C-6.68510254 11.99873047 -7.13192383 12.57558594 -7.59228516 13.16992188 C-9.56044812 15.72860199 -11.48925042 18.31593331 -13.41943359 20.90332031 C-15.93655042 24.27620829 -18.46798471 27.63828945 -21 31 C-21.73162354 31.97259766 -21.73162354 31.97259766 -22.47802734 32.96484375 C-23.85581766 34.79255338 -25.23931786 36.61576941 -26.625 38.4375 C-27.42164063 39.48808594 -28.21828125 40.53867188 -29.0390625 41.62109375 C-31 44 -31 44 -33 45 C-31.54990614 40.73547666 -29.41610759 37.70574079 -26.625 34.1875 C-25.72420879 33.04119019 -24.82451948 31.89401386 -23.92578125 30.74609375 C-23.21349365 29.83899658 -23.21349365 29.83899658 -22.48681641 28.91357422 C-19.88186953 25.56093487 -17.35080221 22.15319629 -14.8125 18.75 C-3.12797339 3.12797339 -3.12797339 3.12797339 0 0 Z " fill="#0DC260" transform="translate(1552,1259)"/>
<path d="M0 0 C0 3.99234494 -1.42869817 5.18478884 -3.875 8.3125 C-4.70984167 9.3946714 -5.54311699 10.47805258 -6.375 11.5625 C-7.02662109 12.40941406 -7.02662109 12.40941406 -7.69140625 13.2734375 C-9.81511979 16.07547148 -11.84355718 18.94324423 -13.875 21.8125 C-14.70666567 22.9794273 -15.53870363 24.14608935 -16.37109375 25.3125 C-17.73818886 27.22882336 -19.10368027 29.14620956 -20.46533203 31.06640625 C-21.94870966 33.15380256 -23.44208852 35.23371371 -24.9375 37.3125 C-25.39817871 37.96516846 -25.85885742 38.61783691 -26.33349609 39.2902832 C-29.65835146 43.88611715 -29.65835146 43.88611715 -33 45 C-31.72680443 42.30879389 -30.33905096 39.96461661 -28.53125 37.6015625 C-28.04744873 36.96420166 -27.56364746 36.32684082 -27.06518555 35.67016602 C-26.54867432 34.99526123 -26.03216309 34.32035645 -25.5 33.625 C-21.4806195 28.32587106 -17.52707318 22.99339628 -13.6875 17.5625 C-4.27091369 4.27091369 -4.27091369 4.27091369 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.48046875 1.87109375 3.48046875 1.87109375 5.1875 4.4375 C8.0928836 8.71118667 11.13543954 12.80960229 14.328125 16.87109375 C18.75370152 22.50646572 22.95481629 28.29953431 27.125 34.125 C27.54499268 34.71112061 27.96498535 35.29724121 28.39770508 35.90112305 C31.0041561 39.55551267 33.52854089 43.25294909 36 47 C33.02271967 45.69724211 31.31349963 44.49230891 29.40625 41.8671875 C28.93928711 41.23393555 28.47232422 40.60068359 27.99121094 39.94824219 C27.49911133 39.26407227 27.00701172 38.57990234 26.5 37.875 C25.43263379 36.41901996 24.36491534 34.9632981 23.296875 33.5078125 C22.75224609 32.76047852 22.20761719 32.01314453 21.64648438 31.24316406 C19.55403076 28.3924132 17.41574682 25.57804441 15.27636719 22.76245117 C0 2.62120122 0 2.62120122 0 0 Z " fill="#0DC260" transform="translate(390,1119)"/>
<path d="M0 0 C0.495 0.99 0.495 0.99 1 2 C0.46632813 2.70382812 -0.06734375 3.40765625 -0.6171875 4.1328125 C-4.7581594 9.62067492 -8.83803838 15.14026725 -12.8125 20.75 C-18.39183767 28.61304526 -24.17549805 36.31751802 -30 44 C-30.74121094 44.98226562 -31.48242188 45.96453125 -32.24609375 46.9765625 C-33.17615234 48.19472656 -33.17615234 48.19472656 -34.125 49.4375 C-34.64320312 50.11683594 -35.16140625 50.79617188 -35.6953125 51.49609375 C-37 53 -37 53 -39 54 C-37.73351701 51.32663783 -36.35872407 48.98783209 -34.56640625 46.63671875 C-33.84904297 45.68937866 -33.84904297 45.68937866 -33.1171875 44.72290039 C-32.60414062 44.05121826 -32.09109375 43.37953613 -31.5625 42.6875 C-30.46943898 41.24265112 -29.37700455 39.79732802 -28.28515625 38.3515625 C-27.73359863 37.62227539 -27.18204102 36.89298828 -26.61376953 36.14160156 C-24.22006805 32.96496776 -21.85383748 29.76875244 -19.5 26.5625 C-19.05994629 25.96308594 -18.61989258 25.36367188 -18.16650391 24.74609375 C-13.99517535 19.03748354 -9.92595062 13.25722305 -5.8828125 7.45727539 C-5.16544922 6.43234985 -5.16544922 6.43234985 -4.43359375 5.38671875 C-4.01134521 4.78045654 -3.58909668 4.17419434 -3.15405273 3.54956055 C-2 2 -2 2 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.77930427 4.98275356 -7.89432435 8.45606043 -13 12 C-13.7734375 12.5465625 -14.546875 13.093125 -15.34375 13.65625 C-21.62632327 18.09593511 -28.00931818 22.37453192 -34.42578125 26.6171875 C-36.59283051 28.0527361 -38.72836028 29.51214389 -40.85546875 31.0078125 C-42.04076172 31.83925781 -42.04076172 31.83925781 -43.25 32.6875 C-43.91515625 33.16574219 -44.5803125 33.64398437 -45.265625 34.13671875 C-47 35 -47 35 -50 34 C-49.05793701 33.37544922 -48.11587402 32.75089844 -47.14526367 32.10742188 C-43.59692322 29.75407453 -40.05073106 27.3975066 -36.50512695 25.04003906 C-34.98030604 24.02681139 -33.45493025 23.01441815 -31.92895508 22.00292969 C-23.89485818 16.67674795 -15.90926427 11.32892639 -8.16210938 5.58984375 C-5.49821709 3.63102865 -2.77354222 1.79905441 0 0 Z " fill="#0DC260" transform="translate(1262,1725)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.09192462 4.2293461 -1.23074255 6.31155714 -2.5 8.4375 C-2.87020264 9.06567627 -3.24040527 9.69385254 -3.62182617 10.34106445 C-4.38228515 11.62500065 -5.1468658 12.90650448 -5.91552734 14.18554688 C-6.86492959 15.77401097 -7.78821576 17.37802481 -8.70703125 18.984375 C-13.57277616 27.17682142 -20.59472291 36.9950649 -30 40 C-26.57368618 35.85235695 -23.05846555 32.10994854 -19.125 28.4375 C-14.17582261 23.56263458 -11.06901407 18.41845085 -7.828125 12.36328125 C-5.48374537 8.05022385 -2.808364 4.02106664 0 0 Z " fill="#0DC260" transform="translate(1294,1685)"/>
<path d="M0 0 C0 4.96076816 -3.70609257 7.52309772 -7 11 C-7.45020508 11.47743652 -7.90041016 11.95487305 -8.36425781 12.44677734 C-14.41125839 18.8162035 -20.3241597 24.5805768 -28 29 C-28.66 28.67 -29.32 28.34 -30 28 C-29.4013916 27.54431641 -28.8027832 27.08863281 -28.18603516 26.61914062 C-21.42258811 21.35504437 -15.37230867 15.61281239 -9.375 9.5 C-8.46621094 8.5821875 -7.55742188 7.664375 -6.62109375 6.71875 C-4.40935522 4.48373001 -2.20247028 2.2441473 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C1 3 1 3 0.06640625 5.20703125 C-0.67802734 6.49673828 -0.67802734 6.49673828 -1.4375 7.8125 C-2.27861328 9.28976562 -2.27861328 9.28976562 -3.13671875 10.796875 C-3.75160156 11.85390625 -4.36648438 12.9109375 -5 14 C-6.25086158 16.18700745 -7.50082204 18.37453047 -8.75 20.5625 C-9.07605225 21.13025146 -9.40210449 21.69800293 -9.73803711 22.28295898 C-14.24535052 30.13996979 -18.61485868 38.07439622 -23 46 C-23.99 46 -24.98 46 -26 46 C-25.63648438 45.40574219 -25.27296875 44.81148437 -24.8984375 44.19921875 C-21.66368637 38.86602651 -18.59435478 33.47330677 -15.6328125 27.984375 C-13.79819816 24.63115644 -11.90490468 21.31354341 -10 18 C-6.57917293 12.04668115 -3.25669739 6.04462774 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C4.65493075 3.27788227 7.42290802 7.10813577 10.5625 11.75 C15.25090056 18.55740994 20.09413207 25.20623775 25.16625977 31.73339844 C27.69700716 35.04114856 29.69728518 37.98457313 31 42 C26.95211837 38.15856771 23.62027498 34.04937522 20.3125 29.5625 C19.79429687 28.86600342 19.27609375 28.16950684 18.7421875 27.4519043 C14.86136976 22.21718881 11.04994532 16.93359846 7.2980957 11.60571289 C5.51005962 9.0729485 3.69085013 6.62467936 1.71875 4.23046875 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(284,976)"/>
<path d="M0 0 C6.18134869 5.10448822 11.79822878 10.68294942 17.4375 16.375 C18.35982422 17.30183594 19.28214844 18.22867187 20.23242188 19.18359375 C22.49058625 21.45345846 24.74636942 23.72563538 27 26 C19.96300327 26 13.4594101 16.60865459 8.625 11.875 C8.00584717 11.2773584 7.38669434 10.6797168 6.7487793 10.06396484 C3.58062768 6.91894479 1.24892948 4.41288415 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C-1.56282982 3.76603869 -3.9063475 6.13639151 -6.7890625 8.984375 C-7.25234955 9.44483215 -7.7156366 9.90528931 -8.19296265 10.37969971 C-9.66565898 11.84125078 -11.14517403 13.29567168 -12.625 14.75 C-13.62806322 15.74302611 -14.63067257 16.73651089 -15.6328125 17.73046875 C-18.08330835 20.15897941 -20.5399667 22.58114675 -23 25 C-23.33 24.01 -23.66 23.02 -24 22 C-20.90984779 18.86050859 -17.81325304 15.72756243 -14.71044922 12.60058594 C-13.65525491 11.5353174 -12.60186036 10.46826303 -11.55029297 9.39941406 C-10.04080273 7.86573784 -8.52501301 6.33854432 -7.0078125 4.8125 C-6.09660645 3.89082031 -5.18540039 2.96914063 -4.24658203 2.01953125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C0.94939453 0.95326172 0.94939453 0.95326172 1.91796875 1.92578125 C4.40684041 4.41640873 6.91556844 6.88636378 9.42578125 9.35546875 C11.05480558 10.96602641 12.68370884 12.57670653 14.3125 14.1875 C15.56643555 15.41629883 15.56643555 15.41629883 16.84570312 16.66992188 C17.63525391 17.45302734 18.42480469 18.23613281 19.23828125 19.04296875 C20.321698 20.11067505 20.321698 20.11067505 21.42700195 21.19995117 C23 23 23 23 23 25 C19.68545526 23.55480663 17.50259028 21.74845019 14.9609375 19.19140625 C14.21585938 18.44439453 13.47078125 17.69738281 12.703125 16.92773438 C11.93484375 16.14720703 11.1665625 15.36667969 10.375 14.5625 C9.59898438 13.78583984 8.82296875 13.00917969 8.0234375 12.20898438 C0 4.12286377 0 4.12286377 0 0 Z " fill="#0DC260" transform="translate(1740,946)"/>
<path d="M0 0 C5.44302277 1.53085015 8.92878538 5.2900022 13 9 C14.37403608 10.16780177 15.74901722 11.3344926 17.125 12.5 C20.81795255 15.71856141 23.90425351 19.20771054 27 23 C26.67 23.66 26.34 24.32 26 25 C25.59273682 24.58226318 25.18547363 24.16452637 24.76586914 23.73413086 C14.77635583 13.36838734 14.77635583 13.36838734 3.63671875 4.296875 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.42032471 1.55349121 0.84064941 2.10698242 0.2434082 2.67724609 C-2.41374893 5.22949798 -5.0505307 7.80190193 -7.6875 10.375 C-8.59951172 11.24511719 -9.51152344 12.11523438 -10.45117188 13.01171875 C-16.07537506 18.5336637 -20.04369605 23.66599722 -23 31 C-24.14306641 27.32226562 -24.14306641 27.32226562 -22.85546875 24.421875 C-22.30503906 23.54015625 -21.75460937 22.6584375 -21.1875 21.75 C-20.37345703 20.41195312 -20.37345703 20.41195312 -19.54296875 19.046875 C-19.03378906 18.37140625 -18.52460937 17.6959375 -18 17 C-17.34 17 -16.68 17 -16 17 C-15.74734375 16.40960937 -15.4946875 15.81921875 -15.234375 15.2109375 C-13.8550269 12.74033299 -12.42482424 11.42049443 -10.25 9.625 C-6.6385246 6.5736987 -3.30090396 3.38342656 0 0 Z " fill="#0DC260" transform="translate(1456,953)"/>
<path d="M0 0 C4.82783324 2.15560327 8.0018426 5.67180855 11.6875 9.375 C12.72100586 10.38433594 12.72100586 10.38433594 13.77539062 11.4140625 C14.75862305 12.39632812 14.75862305 12.39632812 15.76171875 13.3984375 C16.35944092 13.99317871 16.95716309 14.58791992 17.57299805 15.20068359 C19.11683706 17.14732063 19.59286755 18.57190081 20 21 C15.09312847 17.0060348 10.55729437 12.6959047 6.0625 8.25 C5.47057861 7.67096924 4.87865723 7.09193848 4.26879883 6.49536133 C2.80590875 5.03589071 1.39785485 3.52187506 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-3.17703948 6.83444132 -8.40280876 12.56478535 -14 18 C-14.66 17.67 -15.32 17.34 -16 17 C-10.94647258 11.03651266 -5.58288259 5.46894621 0 0 Z " fill="#0DC260" transform="translate(300,954)"/>
<path d="M0 0 C5.48366593 2.02258932 9.90145405 5.13740049 14.6875 8.4375 C15.9878418 9.31631836 15.9878418 9.31631836 17.31445312 10.21289062 C18.14267578 10.78072266 18.97089844 11.34855469 19.82421875 11.93359375 C20.95476685 12.7078772 20.95476685 12.7078772 22.1081543 13.49780273 C24 15 24 15 26 18 C22.36210749 16.6800567 19.44577388 15.07570775 16.3125 12.8125 C11.89277787 9.64038712 7.42860768 6.54493223 2.93359375 3.48046875 C1 2 1 2 0 0 Z " fill="#0DC260" transform="translate(802,1737)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.32195312 1.4846875 0.64390625 1.969375 -0.0546875 2.46875 C-6.5266874 7.13002417 -12.8194913 11.95906449 -19 17 C-19.66 16.67 -20.32 16.34 -21 16 C-14.46357242 9.79369503 -7.594442 4.83165853 0 0 Z " fill="#0DC260" transform="translate(1559,871)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.48657473 5.28497559 -1.97988554 7.32947939 -3.6875 9.4375 C-4.13544922 10.01048828 -4.58339844 10.58347656 -5.04492188 11.17382812 C-7.52724234 14.31376478 -10.09714142 17.2331067 -13 20 C-13 15.81198866 -10.69900914 13.68878746 -8.1875 10.5625 C-7.28506413 9.41804138 -6.38271824 8.27351181 -5.48046875 7.12890625 C-4.66191406 6.09636719 -3.84335938 5.06382813 -3 4 C-1.99415118 2.6710734 -0.99102203 1.34001982 0 0 Z " fill="#0DC260" transform="translate(1686,1080)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.83333333 2.02083333 -0.33333333 3.04166667 -1.5 4.0625 C-2.22574219 4.69800781 -2.95148438 5.33351563 -3.69921875 5.98828125 C-5.19987905 7.30040359 -6.70239882 8.61040322 -8.20703125 9.91796875 C-8.90183594 10.52253906 -9.59664062 11.12710938 -10.3125 11.75 C-10.94800781 12.30171875 -11.58351563 12.8534375 -12.23828125 13.421875 C-13.88505175 14.89703084 -15.45376207 16.42045848 -17 18 C-17.66 17.67 -18.32 17.34 -19 17 C-17.33333333 15.33333333 -15.66666667 13.66666667 -14 12 C-13.236875 11.195625 -12.47375 10.39125 -11.6875 9.5625 C-8.83906474 6.8465501 -5.84703925 4.5500963 -2.671875 2.234375 C-1.05529654 1.10491666 -1.05529654 1.10491666 0 0 Z " fill="#0DC260" transform="translate(1493,922)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.0390625 4.25 -0.0390625 4.25 -1.625 7 C-4.24920071 11.61518362 -6.6099927 16.27744115 -8.82421875 21.1015625 C-10 23 -10 23 -13 24 C-11.20469881 18.95263894 -8.55008635 14.40609448 -5.9375 9.75 C-5.47794922 8.92242188 -5.01839844 8.09484375 -4.54492188 7.2421875 C-1.13705937 1.13705937 -1.13705937 1.13705937 0 0 Z " fill="#0DC260" transform="translate(1385,1523)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.60770997 3.73202093 -0.78900556 5.46048484 -2.1875 7.1875 C-2.96480469 8.15042969 -3.74210937 9.11335938 -4.54296875 10.10546875 C-6.91808927 12.90350421 -9.37082777 15.4455467 -12 18 C-10.46906512 13.32800909 -7.89242605 9.97829995 -4.875 6.1875 C-4.40707031 5.59001953 -3.93914062 4.99253906 -3.45703125 4.37695312 C-2.30994435 2.91383208 -1.15568766 1.45633703 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C3.27971932 3.02743322 5.83952114 6.38308979 8.47265625 9.9609375 C10.54799611 12.73159583 12.75836664 15.36278428 15 18 C10.65299804 16.63444965 8.60531597 14.81529698 5.8125 11.25 C5.13832031 10.40953125 4.46414063 9.5690625 3.76953125 8.703125 C1.9116764 5.86507741 0.92661416 3.25027735 0 0 Z " fill="#0DC260" transform="translate(763,1703)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945312 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C11.34 10.66 10.68 11.32 10 12 C8.32737283 10.38113585 6.66204463 8.7547271 5 7.125 C4.071875 6.22007812 3.14375 5.31515625 2.1875 4.3828125 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1709,915)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945313 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C8.28053558 10 7.59485764 9.11128458 4.875 6.6875 C4.17117188 6.07261719 3.46734375 5.45773437 2.7421875 4.82421875 C1 3 1 3 0 0 Z " fill="#0DC260" transform="translate(896,1589)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.30368347 4.68996005 -1.64444707 6.35135455 -3 8 C-4.44399479 10.6157212 -5.73708895 13.29280238 -7 16 C-7.67578125 14.328125 -7.67578125 14.328125 -8 12 C-6.85546875 9.421875 -6.85546875 9.421875 -5.1875 6.75 C-4.64480469 5.85796875 -4.10210938 4.9659375 -3.54296875 4.046875 C-3.03378906 3.37140625 -2.52460937 2.6959375 -2 2 C-1.34 2 -0.68 2 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1440,968)"/>
<path d="M0 0 C-1.38188453 3.21043882 -2.92421903 5.04936365 -5.625 7.25 C-6.57246094 8.03117188 -6.57246094 8.03117188 -7.5390625 8.828125 C-8.02117187 9.21484375 -8.50328125 9.6015625 -9 10 C-9 7 -9 7 -7.5390625 5.17578125 C-6.90742188 4.56089844 -6.27578125 3.94601562 -5.625 3.3125 C-4.68527344 2.37857422 -4.68527344 2.37857422 -3.7265625 1.42578125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C3.21043882 1.38188453 5.04936365 2.92421903 7.25 5.625 C8.03117187 6.57246094 8.03117187 6.57246094 8.828125 7.5390625 C9.40820312 8.26222656 9.40820312 8.26222656 10 9 C7 9 7 9 5.17578125 7.5390625 C4.56089844 6.90742187 3.94601562 6.27578125 3.3125 5.625 C2.68988281 4.99851562 2.06726562 4.37203125 1.42578125 3.7265625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1700,906)"/>
<path d="M0 0 C7.91607732 6.31117397 7.91607732 6.31117397 10 11 C9.67 11.66 9.34 12.32 9 13 C7.4941255 11.21326795 5.9954515 9.42046492 4.5 7.625 C3.6646875 6.62726563 2.829375 5.62953125 1.96875 4.6015625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(426,1167)"/>
<path d="M0 0 C0 3.80205426 -1.2000969 5.11156561 -3.375 8.1875 C-4.00148438 9.08855469 -4.62796875 9.98960938 -5.2734375 10.91796875 C-6.12808594 11.94857422 -6.12808594 11.94857422 -7 13 C-7.66 13 -8.32 13 -9 13 C-7.47987323 7.59510481 -3.72614782 4.01507372 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C4.20240011 3.71750779 6.99782679 8.31660979 10 13 C6.63834194 11.58956521 4.90494768 9.98473966 2.75 7.0625 C2.22921875 6.37285156 1.7084375 5.68320313 1.171875 4.97265625 C0 3 0 3 0 0 Z " fill="#0DC260" transform="translate(416,1153)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.21255542 4.22997426 -6.36291061 7.39163722 -11 10 C-9.54144353 6.31353859 -7.69770955 4.83856029 -4.375 2.75 C-3.55773437 2.22921875 -2.74046875 1.7084375 -1.8984375 1.171875 C-1.27195312 0.78515625 -0.64546875 0.3984375 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C1 3 1 3 -0.21484375 5.69921875 C-0.78332031 6.68535156 -1.35179687 7.67148438 -1.9375 8.6875 C-2.50339844 9.68136719 -3.06929687 10.67523437 -3.65234375 11.69921875 C-4.31943359 12.83810547 -4.31943359 12.83810547 -5 14 C-5.66 14 -6.32 14 -7 14 C-4.66666667 9.33333333 -2.33333333 4.66666667 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.11678083 3.6721852 -1.24366352 5.33762803 -2.375 7 C-3.00148438 7.928125 -3.62796875 8.85625 -4.2734375 9.8125 C-4.84320312 10.534375 -5.41296875 11.25625 -6 12 C-6.66 12 -7.32 12 -8 12 C-6.59023295 8.96147295 -4.91129772 6.4060405 -2.875 3.75 C-2.06675781 2.69039062 -2.06675781 2.69039062 -1.2421875 1.609375 C-0.83226562 1.07828125 -0.42234375 0.5471875 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C4.98012761 1.50912958 8.24259942 4.55661849 12 8 C11.01 8.33 10.02 8.66 9 9 C7.49704815 7.69088122 5.99770689 6.37761608 4.5 5.0625 C3.6646875 4.33160156 2.829375 3.60070312 1.96875 2.84765625 C1.3190625 2.23792969 0.669375 1.62820313 0 1 C0 0.67 0 0.34 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0 3.58912412 -0.66436554 4.10857029 -3 6.6875 C-3.556875 7.31011719 -4.11375 7.93273438 -4.6875 8.57421875 C-5.120625 9.04472656 -5.55375 9.51523438 -6 10 C-6.33 9.01 -6.66 8.02 -7 7 C-4.69 4.69 -2.38 2.38 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.14453125 5.0078125 -0.14453125 5.0078125 -1.8125 7.125 C-2.62654297 8.18074219 -2.62654297 8.18074219 -3.45703125 9.2578125 C-5 11 -5 11 -7 12 C-5.62567077 7.99153975 -3.7110562 5.23577676 -1 2 C-0.67 1.34 -0.34 0.68 0 0 Z " fill="#0DC260" transform="translate(1653,1123)"/>
<path d="M0 0 C3.36179774 1.44077046 5.59156268 3.24750021 8 6 C8 6.66 8 7.32 8 8 C4.63820226 6.55922954 2.40843732 4.75249979 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1755,963)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-5.11389522 7.70387244 -5.11389522 7.70387244 -10 8 C-6.97727468 4.74475735 -3.74281699 2.38179263 0 0 Z " fill="#0DC260" transform="translate(1181,1779)"/>
<path d="M0 0 C-1.49097658 3.7952131 -3.75700849 5.61042731 -7 8 C-7.66 7.67 -8.32 7.34 -9 7 C-7.88121617 5.82737096 -6.75476949 4.66204862 -5.625 3.5 C-4.68527344 2.52546875 -4.68527344 2.52546875 -3.7265625 1.53125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(1273,1717)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C-1.3 4.31 -4.6 6.62 -8 9 C-8.66 8.67 -9.32 8.34 -10 8 C-6.7 5.36 -3.4 2.72 0 0 Z " fill="#0DC260" transform="translate(1144,1595)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.87970983 2.48273699 -0.24638618 3.96108886 -1.375 5.4375 C-2.00148438 6.26121094 -2.62796875 7.08492187 -3.2734375 7.93359375 C-5 10 -5 10 -7 11 C-5.5140084 6.40693504 -3.14985318 3.56430755 0 0 Z " fill="#0DC260" transform="translate(1629,1156)"/>
<path d="M0 0 C3.7952131 1.49097658 5.61042731 3.75700849 8 7 C5 7 5 7 2.3125 4.625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C1.17539996 0.92652701 2.34010577 1.86663387 3.5 2.8125 C4.1496875 3.33457031 4.799375 3.85664062 5.46875 4.39453125 C7 6 7 6 7 9 C3.26115668 6.34345343 1.35021826 4.41889613 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.02 4.31 -1.96 6.62 -4 9 C-4.33 8.34 -4.66 7.68 -5 7 C-3.35 4.69 -1.7 2.38 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C-1.39332574 3.36720387 -2.9789286 4.9859524 -6 7 C-6 4 -6 4 -4.125 1.8125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(334,920)"/>
</svg>

After

Width:  |  Height:  |  Size: 92 KiB

+56 -3
View File
@@ -1,4 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2 L22 7 L22 17 L12 22 L2 17 L2 7 Z" />
<text x="12" y="15" text-anchor="middle" font-size="9" font-family="sans-serif" font-weight="bold" fill="currentColor" stroke="none">V</text>
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="2048" height="2048">
<path d="M0 0 C1.43859375 -0.00386719 1.43859375 -0.00386719 2.90625 -0.0078125 C5.5 0.125 5.5 0.125 8.5 1.125 C10.07494679 1.21669387 11.65351919 1.25137572 13.23113275 1.25215852 C14.21223816 1.25507056 15.19334358 1.25798259 16.20417947 1.26098287 C17.82819537 1.25816256 17.82819537 1.25816256 19.48501968 1.25528526 C20.63616652 1.25722869 21.78731336 1.25917212 22.97334343 1.26117444 C26.18790327 1.26559368 29.40242792 1.26551071 32.61698911 1.26360132 C36.10693665 1.26263044 39.59687675 1.26745584 43.08682132 1.27158034 C49.20990348 1.27802579 55.33297881 1.2807976 61.45606422 1.28120613 C70.56131082 1.28184984 79.66654691 1.28823542 88.77178995 1.29595293 C103.14813112 1.30804145 117.52447181 1.31669674 131.90081661 1.32299107 C154.72058471 1.33301518 177.54033782 1.35226383 200.36009693 1.37453346 C209.13518953 1.38306462 217.91028239 1.39133059 226.68537521 1.39963722 C227.66035547 1.40056223 228.63533572 1.40148724 229.63986083 1.40244028 C252.85870126 1.42444049 276.07754337 1.44422712 299.29638672 1.46289062 C300.31261062 1.4637103 301.32883452 1.46452998 302.37585309 1.4653745 C326.08672853 1.48446028 349.79760389 1.50142152 373.50848389 1.51373291 C374.52825771 1.51426258 375.54803154 1.51479225 376.5987076 1.51533796 C384.81851069 1.51958956 393.03831381 1.52376588 401.25811695 1.52792276 C435.12980914 1.54511112 469.00148086 1.57231006 502.87315546 1.61108314 C507.65434625 1.61654521 512.43553718 1.62187815 517.21672821 1.62712479 C518.62824923 1.62867636 518.62824923 1.62867636 520.06828583 1.63025927 C535.22952948 1.64660069 550.39075882 1.65211397 565.55201044 1.65342245 C580.78324492 1.65492508 596.01444047 1.6670549 611.24565777 1.69017886 C620.30022251 1.70358381 629.35470229 1.70856296 638.40927478 1.7016325 C644.45363612 1.69782031 650.497922 1.7048069 656.54226363 1.72064828 C659.98877247 1.72936664 663.4351068 1.73330374 666.88161829 1.72407441 C670.59179392 1.71663549 674.30147582 1.72747849 678.01161575 1.74303246 C679.08492836 1.73646991 680.15824097 1.72990737 681.2640782 1.72314596 C687.16414252 1.77028764 691.25210961 2.40563744 696.5 5.125 C699.01036535 5.9108535 701.53016035 6.59954783 704.0703125 7.28125 C706.5 8.125 706.5 8.125 708.81640625 9.55078125 C712.15660838 11.51017202 715.65183927 12.6206182 719.3125 13.8125 C725.12314078 15.78005859 730.57365124 18.01662951 736 20.875 C743.91548995 25.03164703 752.13060775 28.29606801 760.45703125 31.53613281 C767.24833937 34.18465636 773.88894678 37.05565422 780.5 40.125 C781.62792969 40.62644531 782.75585938 41.12789063 783.91796875 41.64453125 C789.87544004 44.42580487 794.18929719 47.33005411 798.62890625 52.17578125 C801.08514877 54.73458087 803.83225627 56.69473172 806.69921875 58.765625 C809.20702548 60.65871988 811.3078776 62.87807454 813.5 65.125 C815.44546571 66.87634115 817.41886327 68.59202216 819.3984375 70.3046875 C820.76539079 71.48870281 822.12521267 72.68101917 823.4765625 73.8828125 C827.55869277 77.50956569 831.7547855 80.91687025 836.08203125 84.24609375 C843.81041205 90.25150759 851.22731444 96.579583 858.5 103.125 C862.79301203 106.96166823 867.14571406 110.64678818 871.6875 114.1875 C875.54211521 117.23464994 878.45427389 120.29608718 881.5 124.125 C883.69250727 126.02122251 885.95622437 127.73591916 888.3125 129.421875 C892.8061002 132.68675639 896.64337693 136.21058322 900.5078125 140.1953125 C902.37665424 142.00552391 904.25777473 143.49498445 906.375 145 C909.75743286 147.42739299 912.59207175 150.14592977 915.5 153.125 C918.98022329 156.68492306 922.46095715 159.74889797 926.50390625 162.63671875 C930.39058911 165.53461732 933.90514203 168.87823568 937.5 172.125 C938.83079361 173.29456285 940.1640428 174.46133886 941.5 175.625 C945.11855573 178.78405659 948.70954679 181.97304518 952.29296875 185.171875 C953.66010228 186.38172768 955.03611085 187.5817273 956.42578125 188.765625 C960.74873375 192.45311243 964.90660118 196.31083127 969 200.25 C969.54116455 200.75305664 970.0823291 201.25611328 970.63989258 201.77441406 C972.99660725 204.07990406 974.40476361 205.5678671 974.96875 208.8671875 C974.5 211.125 974.5 211.125 972.5 213.125 C970.61562687 213.85104698 968.70207313 214.50219769 966.77734375 215.11328125 C965.60856689 215.48694824 964.43979004 215.86061523 963.2355957 216.24560547 C961.98222412 216.63893066 960.72885254 217.03225586 959.4375 217.4375 C958.1381504 217.85006252 956.83891587 218.26298758 955.53979492 218.67626953 C948.5355565 220.89675968 941.51300334 223.022592 934.44506836 225.03051758 C925.80854358 227.53971466 917.31020977 230.50140017 908.78790283 233.3694458 C900.95847523 236.00276091 893.1395024 238.63053102 885.1875 240.875 C878.27824501 242.83179209 871.55683625 245.19016733 864.79760742 247.61035156 C859.89923627 249.34437211 855.03775758 250.85190074 850 252.125 C834.43818465 256.15515457 821.00057835 260.7909593 808.5 271.125 C807.82066406 271.68316406 807.14132812 272.24132812 806.44140625 272.81640625 C805.34654654 273.74438203 804.26232429 274.68511918 803.19140625 275Line truncated
<path d="M0 0 C1.87410553 -0.02882263 1.87410553 -0.02882263 3.78607178 -0.05822754 C5.15066794 -0.06793431 6.51527271 -0.0764893 7.87988281 -0.08398438 C8.57336067 -0.08963913 9.26683853 -0.09529388 9.98133087 -0.10112 C13.66318779 -0.13109726 17.34488861 -0.14955102 21.02685547 -0.15820312 C24.04330478 -0.16692515 27.05859457 -0.19451452 30.07470703 -0.24023438 C62.05878142 -0.71603308 62.05878142 -0.71603308 74.83300781 6.32226562 C76.23824707 7.05388916 76.23824707 7.05388916 77.671875 7.80029297 C84.94627824 11.73996458 91.37540913 17.1855858 97.83300781 22.32226562 C99.16912109 23.381875 99.16912109 23.381875 100.53222656 24.46289062 C102.97193019 26.40852554 105.40246586 28.36520587 107.83300781 30.32226562 C108.68894531 31.00289062 109.54488281 31.68351563 110.42675781 32.38476562 C114.07474911 35.28557799 117.70690062 38.18252129 121.20800781 41.25976562 C124.22123139 43.87688469 127.37956066 46.25482674 130.58300781 48.63476562 C139.60741948 55.34377755 148.26891224 62.50597841 156.68457031 69.96289062 C161.16621103 73.92673221 165.76834253 77.69602372 170.45410156 81.41601562 C173.06943739 83.51171987 175.62630974 85.66038343 178.15332031 87.86132812 C179.26285929 88.826369 180.38259248 89.77982681 181.51269531 90.72070312 C203.40427145 109.22988982 203.40427145 109.22988982 207.83300781 121.32226562 C208.66275 123.30294052 209.49627508 125.28203372 210.33300781 127.25976562 C210.95755859 128.7834375 210.95755859 128.7834375 211.59472656 130.33789062 C214.15847576 136.51676882 217.00177331 142.56655147 219.85644531 148.61523438 C220.21311279 149.37102783 220.56978027 150.12682129 220.93725586 150.90551758 C221.64534326 152.40356049 222.355073 153.9008285 223.06665039 155.3972168 C227.83300781 165.4610834 227.83300781 165.4610834 227.83300781 170.32226562 C228.49300781 170.32226562 229.15300781 170.32226562 229.83300781 170.32226562 C230.22488281 171.41539062 230.61675781 172.50851562 231.02050781 173.63476562 C232.27815493 177.00030017 233.69377481 180.25201513 235.20800781 183.50976562 C237.60158636 188.67069475 239.60270713 193.9264454 241.52441406 199.27929688 C242.75369103 202.39742165 242.75369103 202.39742165 244.77832031 205.20898438 C247.13673802 208.7824804 248.60778549 212.34747542 250.14550781 216.32226562 C252.28246549 221.68767498 254.54076046 226.87949172 257.20800781 232.00976562 C260.84932475 239.07820438 263.80178067 246.38143656 266.72509766 253.7722168 C268.49135184 258.20522266 270.302487 262.26333909 272.83300781 266.32226562 C273.60406487 268.1804314 274.32999022 270.05769041 275.02050781 271.94726562 C279.63140189 284.18280082 284.607226 296.26409502 290.59863281 307.89257812 C292.16373794 310.97325973 293.47925323 314.1438853 294.83300781 317.32226562 C295.61745301 318.88840358 296.40987243 320.45055997 297.20800781 322.00976562 C299.58916087 326.70790894 301.59351132 331.51049921 303.58300781 336.38476562 C304.73625522 339.09489704 305.98949153 341.70240887 307.33300781 344.32226562 C310.16255909 349.85757531 312.49369373 355.56622466 314.83300781 361.32226562 C317.99874712 369.05833847 321.32809375 376.7069447 324.75024414 384.33203125 C327.05552171 389.49585301 329.22450609 394.70052878 331.33300781 399.94726562 C334.21213545 407.08170247 337.53898567 413.92075478 341.03222656 420.77148438 C346.83300781 432.20946736 346.83300781 432.20946736 346.83300781 436.32226562 C347.49300781 436.32226562 348.15300781 436.32226562 348.83300781 436.32226562 C349.1359375 437.1446875 349.43886719 437.96710938 349.75097656 438.81445312 C351.73651914 444.10516043 353.72451414 449.30402066 356.33300781 454.32226562 C358.82082889 459.11909563 360.69649102 464.06501504 362.59472656 469.11914062 C364.05383396 472.89348783 365.69874287 476.54824977 367.40332031 480.21679688 C368.48238788 482.56067314 369.53787919 484.90920718 370.57519531 487.27148438 C374.24836792 495.63261176 378.04976242 503.91033614 382.02050781 512.13476562 C385.24537657 518.82085247 388.14633604 525.47021049 390.70410156 532.43945312 C392.26792911 536.4328951 394.22040473 540.18335657 396.18066406 543.99414062 C398.1034708 547.86702796 399.84895607 551.79971734 401.58300781 555.75976562 C404.56190043 562.55201713 407.68207529 569.26288869 410.89550781 575.94726562 C414.42834028 583.30627766 417.80799145 590.70768437 421.04394531 598.20117188 C423.15888208 603.09453129 425.33705032 607.95917119 427.52050781 612.82226562 C427.88926025 613.64734619 428.2580127 614.47242676 428.63793945 615.32250977 C430.34586501 619.12111197 432.09530728 622.88008087 433.98535156 626.59179688 C435.46163903 629.50950745 436.67072187 632.40284726 437.70800781 635.50976562 C440.00105327 641.98164295 442.88313053 648.12922132 445.83300781 654.32226562 C446.97919244 656.7373483 448.12466916 659.15276519 449.26977539 661.56835938 C450.04006522 663.19155487 450.81194045 664.81399932 451.58569336 666.43554688 C454.08878497 671.69420811 456.48593201 676.99234018 458.83300781 682.32226562 C461.99550894 689.41193233 465.23699803 696.44086054 468.83Line truncated
<path d="M0 0 C5.44333286 1.53093737 8.92825297 5.29018604 13 9 C14.35338261 10.14675931 15.70753684 11.29260864 17.0625 12.4375 C21.64462627 16.44686048 25.45821971 20.99400134 29.38046265 25.63258362 C34.2136011 31.25757669 39.38333733 36.48054236 44.66015625 41.6875 C46.04798169 43.06591387 47.43580107 44.4443339 48.82327175 45.82310486 C52.20679048 49.18389109 55.59581215 52.53911093 58.98754883 55.89160156 C60.90240519 57.78472355 62.81446848 59.68059109 64.72373962 61.5793457 C66.51027671 63.35563876 68.3008835 65.1278513 70.09620667 66.89526367 C74.35703946 71.1384933 78.20739247 75.38633314 81.71757507 80.269104 C83.45492247 82.61401137 85.42886308 84.62111363 87.5234375 86.6484375 C88.31621094 87.42574219 89.10898438 88.20304688 89.92578125 89.00390625 C90.73402344 89.78636719 91.54226563 90.56882812 92.375 91.375 C94.01229839 92.96152945 95.64536337 94.55244365 97.2734375 96.1484375 C97.98935059 96.84114746 98.70526367 97.53385742 99.44287109 98.24755859 C101 100 101 100 101 102 C97.76847648 100.57784217 95.59614267 98.85315081 93.1015625 96.3671875 C92.01101563 95.28050781 92.01101563 95.28050781 90.8984375 94.171875 C90.14820313 93.41390625 89.39796875 92.6559375 88.625 91.875 C87.8825 91.14023437 87.14 90.40546875 86.375 89.6484375 C85.64539062 88.91625 84.91578125 88.1840625 84.1640625 87.4296875 C83.50873535 86.77210449 82.8534082 86.11452148 82.17822266 85.43701172 C80.40676903 83.45509622 78.90545865 81.50615912 77.36254883 79.35375977 C73.42786725 74.03908037 68.74419397 69.53326462 64.03515625 64.91015625 C63.07341827 63.95725701 62.11228386 63.00374827 61.15171814 62.04966736 C57.61754348 58.54196208 54.07249327 55.04531716 50.52764893 51.54840088 C47.52256879 48.58311201 44.5218497 45.61353187 41.52651787 42.63839531 C40.1377354 41.26236732 38.74278986 39.89256827 37.34767151 38.52296448 C32.68049146 33.8915949 28.39133942 29.20890356 24.46846008 23.92750549 C22.24689754 21.01147525 19.73765741 18.43878566 17.125 15.875 C16.61469238 15.36783447 16.10438477 14.86066895 15.57861328 14.33813477 C11.86265546 10.70169682 7.96638614 7.44283837 3.7421875 4.40234375 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.99 0.495 0.99 0.495 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-10.22159357 9.88886962 -20.26620359 19.24636214 -28.94433594 29.45092773 C-33.33817211 34.48296797 -38.06905727 39.16680262 -42.81651497 43.8611145 C-44.44720722 45.47414979 -46.07410308 47.09093049 -47.70005798 48.70874023 C-52.31793061 53.30238803 -56.94152361 57.8902459 -61.56958008 62.47363281 C-64.41544977 65.29255287 -67.25629051 68.11646317 -70.09420586 70.94338989 C-71.16746948 72.0104976 -72.24261966 73.0757117 -73.31978035 74.1388855 C-78.51758323 79.26974787 -83.59728576 84.33132654 -87.79176331 90.34082031 C-89.85752511 93.1775741 -92.35567767 95.56967547 -94.875 98 C-95.37257813 98.48855469 -95.87015625 98.97710938 -96.3828125 99.48046875 C-97.58386954 100.65842854 -98.79123559 101.82995047 -100 103 C-100.66 102.67 -101.32 102.34 -102 102 C-97.66938005 96.88958996 -93.15590527 92.09370778 -88.30859375 87.46875 C-86.43361103 85.46369234 -84.90438774 83.5337759 -83.31016541 81.31732178 C-80.10058647 77.01114969 -76.52866446 73.23952404 -72.72875977 69.45410156 C-72.027117 68.74734787 -71.32547424 68.04059418 -70.60256958 67.31242371 C-68.30394979 65.00001179 -65.99808728 62.69499372 -63.69140625 60.390625 C-62.07985421 58.77518165 -60.46852455 57.15951643 -58.85740662 55.54364014 C-55.48930414 52.16809876 -52.11738238 48.79642904 -48.74291992 45.42724609 C-44.42597845 41.11611025 -40.12053683 36.79368847 -35.81810093 32.46808243 C-32.49728519 29.13251882 -29.16955123 25.80392492 -25.83979607 22.47728729 C-24.24948973 20.88646875 -22.66153521 19.29329543 -21.07602119 17.6977005 C-18.85800961 15.46731558 -16.6306167 13.2467285 -14.40063477 11.02832031 C-13.75262405 10.37266586 -13.10461334 9.71701141 -12.43696594 9.04148865 C-8.57529327 5.22384661 -4.92754094 2.33444496 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.625 5.34765625 -0.625 5.34765625 -3 8.0625 C-5.93698686 11.51830943 -8.75427783 14.94221196 -11.3125 18.6875 C-15.29868574 24.50145294 -19.54276155 30.1095513 -23.7890625 35.734375 C-25.9890044 38.64872406 -28.16907394 41.57660234 -30.3359375 44.515625 C-30.87645752 45.24571777 -31.41697754 45.97581055 -31.97387695 46.72802734 C-33.01261099 48.13184279 -34.04776171 49.53831861 -35.07885742 50.94775391 C-35.54912354 51.58116699 -36.01938965 52.21458008 -36.50390625 52.8671875 C-36.91455322 53.42519043 -37.3252002 53.98319336 -37.74829102 54.55810547 C-39 56 -39 56 -42 58 C-40.57903924 53.77531559 -38.50867165 50.93955733 -35.625 47.5625 C-32.48959794 43.82298385 -29.66696013 40.08933887 -27 36 C-24.70129936 32.97299816 -22.34483765 29.99133556 -20 27 C-16.45233144 22.43871185 -13.16862732 17.77161076 -10 12.9375 C-6.94299635 8.29908484 -3.73419762 4.10761738 0 0 Z " fill="#0DC260" transform="translate(1664,1109)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.34169662 5.05562693 -1.69564379 6.86486955 -3.25 8.75 C-4.18647751 9.92582536 -5.12131468 11.10295862 -6.0546875 12.28125 C-6.78703613 13.19970703 -6.78703613 13.19970703 -7.53417969 14.13671875 C-9.88398864 17.12368442 -12.1336178 20.18123735 -14.375 23.25 C-14.82472168 23.86528564 -15.27444336 24.48057129 -15.73779297 25.11450195 C-19.31788916 30.03099096 -22.85663624 34.97668341 -26.375 39.9375 C-26.86274902 40.62295898 -27.35049805 41.30841797 -27.85302734 42.01464844 C-31.07241726 46.57646529 -34.08918083 51.2356156 -37 56 C-37.33 55.34 -37.66 54.68 -38 54 C-36.55859375 51.2421875 -36.55859375 51.2421875 -34.4375 47.875 C-34.06689453 47.28533447 -33.69628906 46.69566895 -33.31445312 46.08813477 C-30.89736314 42.28455772 -28.3370912 38.65452968 -25.5703125 35.1015625 C-22.85128247 31.46266161 -20.41173412 27.63484565 -17.9296875 23.83203125 C-16.07017303 21.10298673 -14.086559 18.55771748 -12 16 C-11.03492127 14.73428156 -10.07612986 13.46373357 -9.125 12.1875 C-8.6196875 11.51074219 -8.114375 10.83398438 -7.59375 10.13671875 C-7.0678125 9.43160156 -6.541875 8.72648437 -6 8 C-4.87540898 6.49969335 -3.75042464 4.99968142 -2.625 3.5 C-2.12226562 2.8296875 -1.61953125 2.159375 -1.1015625 1.46875 C-0.73804688 0.9840625 -0.37453125 0.499375 0 0 Z " fill="#0DC260" transform="translate(1509,1315)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-11.17878346 10.5868994 -21.73310024 20.90322611 -31.1953125 31.97265625 C-34.61943288 35.81923304 -38.3225033 39.39755425 -42 43 C-42.66 42.34 -43.32 41.68 -44 41 C-38.86950975 35.79321757 -33.72711487 30.59841286 -28.57641602 25.41162109 C-26.82692975 23.64708236 -25.08014983 21.87985596 -23.33618164 20.10986328 C-20.82370575 17.5608501 -18.30153929 15.02177671 -15.77734375 12.484375 C-15.00414291 11.69569031 -14.23094208 10.90700562 -13.43431091 10.09442139 C-9.24303815 5.90186564 -5.4197086 2.47910486 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.19140625 1.328125 3.19140625 1.328125 4.5625 3.25 C5.09101562 3.97960938 5.61953125 4.70921875 6.1640625 5.4609375 C7.07285156 6.71777344 7.07285156 6.71777344 8 8 C9.47680111 9.96011784 10.95610817 11.91834936 12.4375 13.875 C18.89826433 22.51078117 24.95045701 31.36455683 30.875 40.375 C31.45926758 41.25607422 32.04353516 42.13714844 32.64550781 43.04492188 C33.19303711 43.88345703 33.74056641 44.72199219 34.3046875 45.5859375 C34.79952637 46.3392334 35.29436523 47.0925293 35.80419922 47.86865234 C36.96346212 49.93487634 37.55479394 51.68479735 38 54 C35.15497965 51.41843814 33.21663697 48.46505704 31.12109375 45.2578125 C30.36164909 44.10300467 29.60204015 42.94830486 28.84228516 41.79370117 C28.44906067 41.19351166 28.05583618 40.59332214 27.6506958 39.97494507 C21.70740437 30.91230022 15.74825198 21.92928068 8.9453125 13.48046875 C5.60068864 9.21573753 2.74542467 4.66722194 0 0 Z " fill="#0DC260" transform="translate(541,1321)"/>
<path d="M0 0 C0 3.95229679 -1.3349536 5.08305206 -3.75 8.1875 C-4.57984179 9.26530583 -5.40924597 10.34344869 -6.23828125 11.421875 C-6.68510254 11.99873047 -7.13192383 12.57558594 -7.59228516 13.16992188 C-9.56044812 15.72860199 -11.48925042 18.31593331 -13.41943359 20.90332031 C-15.93655042 24.27620829 -18.46798471 27.63828945 -21 31 C-21.73162354 31.97259766 -21.73162354 31.97259766 -22.47802734 32.96484375 C-23.85581766 34.79255338 -25.23931786 36.61576941 -26.625 38.4375 C-27.42164063 39.48808594 -28.21828125 40.53867188 -29.0390625 41.62109375 C-31 44 -31 44 -33 45 C-31.54990614 40.73547666 -29.41610759 37.70574079 -26.625 34.1875 C-25.72420879 33.04119019 -24.82451948 31.89401386 -23.92578125 30.74609375 C-23.21349365 29.83899658 -23.21349365 29.83899658 -22.48681641 28.91357422 C-19.88186953 25.56093487 -17.35080221 22.15319629 -14.8125 18.75 C-3.12797339 3.12797339 -3.12797339 3.12797339 0 0 Z " fill="#0DC260" transform="translate(1552,1259)"/>
<path d="M0 0 C0 3.99234494 -1.42869817 5.18478884 -3.875 8.3125 C-4.70984167 9.3946714 -5.54311699 10.47805258 -6.375 11.5625 C-7.02662109 12.40941406 -7.02662109 12.40941406 -7.69140625 13.2734375 C-9.81511979 16.07547148 -11.84355718 18.94324423 -13.875 21.8125 C-14.70666567 22.9794273 -15.53870363 24.14608935 -16.37109375 25.3125 C-17.73818886 27.22882336 -19.10368027 29.14620956 -20.46533203 31.06640625 C-21.94870966 33.15380256 -23.44208852 35.23371371 -24.9375 37.3125 C-25.39817871 37.96516846 -25.85885742 38.61783691 -26.33349609 39.2902832 C-29.65835146 43.88611715 -29.65835146 43.88611715 -33 45 C-31.72680443 42.30879389 -30.33905096 39.96461661 -28.53125 37.6015625 C-28.04744873 36.96420166 -27.56364746 36.32684082 -27.06518555 35.67016602 C-26.54867432 34.99526123 -26.03216309 34.32035645 -25.5 33.625 C-21.4806195 28.32587106 -17.52707318 22.99339628 -13.6875 17.5625 C-4.27091369 4.27091369 -4.27091369 4.27091369 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.48046875 1.87109375 3.48046875 1.87109375 5.1875 4.4375 C8.0928836 8.71118667 11.13543954 12.80960229 14.328125 16.87109375 C18.75370152 22.50646572 22.95481629 28.29953431 27.125 34.125 C27.54499268 34.71112061 27.96498535 35.29724121 28.39770508 35.90112305 C31.0041561 39.55551267 33.52854089 43.25294909 36 47 C33.02271967 45.69724211 31.31349963 44.49230891 29.40625 41.8671875 C28.93928711 41.23393555 28.47232422 40.60068359 27.99121094 39.94824219 C27.49911133 39.26407227 27.00701172 38.57990234 26.5 37.875 C25.43263379 36.41901996 24.36491534 34.9632981 23.296875 33.5078125 C22.75224609 32.76047852 22.20761719 32.01314453 21.64648438 31.24316406 C19.55403076 28.3924132 17.41574682 25.57804441 15.27636719 22.76245117 C0 2.62120122 0 2.62120122 0 0 Z " fill="#0DC260" transform="translate(390,1119)"/>
<path d="M0 0 C0.495 0.99 0.495 0.99 1 2 C0.46632813 2.70382812 -0.06734375 3.40765625 -0.6171875 4.1328125 C-4.7581594 9.62067492 -8.83803838 15.14026725 -12.8125 20.75 C-18.39183767 28.61304526 -24.17549805 36.31751802 -30 44 C-30.74121094 44.98226562 -31.48242188 45.96453125 -32.24609375 46.9765625 C-33.17615234 48.19472656 -33.17615234 48.19472656 -34.125 49.4375 C-34.64320312 50.11683594 -35.16140625 50.79617188 -35.6953125 51.49609375 C-37 53 -37 53 -39 54 C-37.73351701 51.32663783 -36.35872407 48.98783209 -34.56640625 46.63671875 C-33.84904297 45.68937866 -33.84904297 45.68937866 -33.1171875 44.72290039 C-32.60414062 44.05121826 -32.09109375 43.37953613 -31.5625 42.6875 C-30.46943898 41.24265112 -29.37700455 39.79732802 -28.28515625 38.3515625 C-27.73359863 37.62227539 -27.18204102 36.89298828 -26.61376953 36.14160156 C-24.22006805 32.96496776 -21.85383748 29.76875244 -19.5 26.5625 C-19.05994629 25.96308594 -18.61989258 25.36367188 -18.16650391 24.74609375 C-13.99517535 19.03748354 -9.92595062 13.25722305 -5.8828125 7.45727539 C-5.16544922 6.43234985 -5.16544922 6.43234985 -4.43359375 5.38671875 C-4.01134521 4.78045654 -3.58909668 4.17419434 -3.15405273 3.54956055 C-2 2 -2 2 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.77930427 4.98275356 -7.89432435 8.45606043 -13 12 C-13.7734375 12.5465625 -14.546875 13.093125 -15.34375 13.65625 C-21.62632327 18.09593511 -28.00931818 22.37453192 -34.42578125 26.6171875 C-36.59283051 28.0527361 -38.72836028 29.51214389 -40.85546875 31.0078125 C-42.04076172 31.83925781 -42.04076172 31.83925781 -43.25 32.6875 C-43.91515625 33.16574219 -44.5803125 33.64398437 -45.265625 34.13671875 C-47 35 -47 35 -50 34 C-49.05793701 33.37544922 -48.11587402 32.75089844 -47.14526367 32.10742188 C-43.59692322 29.75407453 -40.05073106 27.3975066 -36.50512695 25.04003906 C-34.98030604 24.02681139 -33.45493025 23.01441815 -31.92895508 22.00292969 C-23.89485818 16.67674795 -15.90926427 11.32892639 -8.16210938 5.58984375 C-5.49821709 3.63102865 -2.77354222 1.79905441 0 0 Z " fill="#0DC260" transform="translate(1262,1725)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.09192462 4.2293461 -1.23074255 6.31155714 -2.5 8.4375 C-2.87020264 9.06567627 -3.24040527 9.69385254 -3.62182617 10.34106445 C-4.38228515 11.62500065 -5.1468658 12.90650448 -5.91552734 14.18554688 C-6.86492959 15.77401097 -7.78821576 17.37802481 -8.70703125 18.984375 C-13.57277616 27.17682142 -20.59472291 36.9950649 -30 40 C-26.57368618 35.85235695 -23.05846555 32.10994854 -19.125 28.4375 C-14.17582261 23.56263458 -11.06901407 18.41845085 -7.828125 12.36328125 C-5.48374537 8.05022385 -2.808364 4.02106664 0 0 Z " fill="#0DC260" transform="translate(1294,1685)"/>
<path d="M0 0 C0 4.96076816 -3.70609257 7.52309772 -7 11 C-7.45020508 11.47743652 -7.90041016 11.95487305 -8.36425781 12.44677734 C-14.41125839 18.8162035 -20.3241597 24.5805768 -28 29 C-28.66 28.67 -29.32 28.34 -30 28 C-29.4013916 27.54431641 -28.8027832 27.08863281 -28.18603516 26.61914062 C-21.42258811 21.35504437 -15.37230867 15.61281239 -9.375 9.5 C-8.46621094 8.5821875 -7.55742188 7.664375 -6.62109375 6.71875 C-4.40935522 4.48373001 -2.20247028 2.2441473 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C1 3 1 3 0.06640625 5.20703125 C-0.67802734 6.49673828 -0.67802734 6.49673828 -1.4375 7.8125 C-2.27861328 9.28976562 -2.27861328 9.28976562 -3.13671875 10.796875 C-3.75160156 11.85390625 -4.36648438 12.9109375 -5 14 C-6.25086158 16.18700745 -7.50082204 18.37453047 -8.75 20.5625 C-9.07605225 21.13025146 -9.40210449 21.69800293 -9.73803711 22.28295898 C-14.24535052 30.13996979 -18.61485868 38.07439622 -23 46 C-23.99 46 -24.98 46 -26 46 C-25.63648438 45.40574219 -25.27296875 44.81148437 -24.8984375 44.19921875 C-21.66368637 38.86602651 -18.59435478 33.47330677 -15.6328125 27.984375 C-13.79819816 24.63115644 -11.90490468 21.31354341 -10 18 C-6.57917293 12.04668115 -3.25669739 6.04462774 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C4.65493075 3.27788227 7.42290802 7.10813577 10.5625 11.75 C15.25090056 18.55740994 20.09413207 25.20623775 25.16625977 31.73339844 C27.69700716 35.04114856 29.69728518 37.98457313 31 42 C26.95211837 38.15856771 23.62027498 34.04937522 20.3125 29.5625 C19.79429687 28.86600342 19.27609375 28.16950684 18.7421875 27.4519043 C14.86136976 22.21718881 11.04994532 16.93359846 7.2980957 11.60571289 C5.51005962 9.0729485 3.69085013 6.62467936 1.71875 4.23046875 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(284,976)"/>
<path d="M0 0 C6.18134869 5.10448822 11.79822878 10.68294942 17.4375 16.375 C18.35982422 17.30183594 19.28214844 18.22867187 20.23242188 19.18359375 C22.49058625 21.45345846 24.74636942 23.72563538 27 26 C19.96300327 26 13.4594101 16.60865459 8.625 11.875 C8.00584717 11.2773584 7.38669434 10.6797168 6.7487793 10.06396484 C3.58062768 6.91894479 1.24892948 4.41288415 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C-1.56282982 3.76603869 -3.9063475 6.13639151 -6.7890625 8.984375 C-7.25234955 9.44483215 -7.7156366 9.90528931 -8.19296265 10.37969971 C-9.66565898 11.84125078 -11.14517403 13.29567168 -12.625 14.75 C-13.62806322 15.74302611 -14.63067257 16.73651089 -15.6328125 17.73046875 C-18.08330835 20.15897941 -20.5399667 22.58114675 -23 25 C-23.33 24.01 -23.66 23.02 -24 22 C-20.90984779 18.86050859 -17.81325304 15.72756243 -14.71044922 12.60058594 C-13.65525491 11.5353174 -12.60186036 10.46826303 -11.55029297 9.39941406 C-10.04080273 7.86573784 -8.52501301 6.33854432 -7.0078125 4.8125 C-6.09660645 3.89082031 -5.18540039 2.96914063 -4.24658203 2.01953125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C0.94939453 0.95326172 0.94939453 0.95326172 1.91796875 1.92578125 C4.40684041 4.41640873 6.91556844 6.88636378 9.42578125 9.35546875 C11.05480558 10.96602641 12.68370884 12.57670653 14.3125 14.1875 C15.56643555 15.41629883 15.56643555 15.41629883 16.84570312 16.66992188 C17.63525391 17.45302734 18.42480469 18.23613281 19.23828125 19.04296875 C20.321698 20.11067505 20.321698 20.11067505 21.42700195 21.19995117 C23 23 23 23 23 25 C19.68545526 23.55480663 17.50259028 21.74845019 14.9609375 19.19140625 C14.21585938 18.44439453 13.47078125 17.69738281 12.703125 16.92773438 C11.93484375 16.14720703 11.1665625 15.36667969 10.375 14.5625 C9.59898438 13.78583984 8.82296875 13.00917969 8.0234375 12.20898438 C0 4.12286377 0 4.12286377 0 0 Z " fill="#0DC260" transform="translate(1740,946)"/>
<path d="M0 0 C5.44302277 1.53085015 8.92878538 5.2900022 13 9 C14.37403608 10.16780177 15.74901722 11.3344926 17.125 12.5 C20.81795255 15.71856141 23.90425351 19.20771054 27 23 C26.67 23.66 26.34 24.32 26 25 C25.59273682 24.58226318 25.18547363 24.16452637 24.76586914 23.73413086 C14.77635583 13.36838734 14.77635583 13.36838734 3.63671875 4.296875 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.42032471 1.55349121 0.84064941 2.10698242 0.2434082 2.67724609 C-2.41374893 5.22949798 -5.0505307 7.80190193 -7.6875 10.375 C-8.59951172 11.24511719 -9.51152344 12.11523438 -10.45117188 13.01171875 C-16.07537506 18.5336637 -20.04369605 23.66599722 -23 31 C-24.14306641 27.32226562 -24.14306641 27.32226562 -22.85546875 24.421875 C-22.30503906 23.54015625 -21.75460937 22.6584375 -21.1875 21.75 C-20.37345703 20.41195312 -20.37345703 20.41195312 -19.54296875 19.046875 C-19.03378906 18.37140625 -18.52460937 17.6959375 -18 17 C-17.34 17 -16.68 17 -16 17 C-15.74734375 16.40960937 -15.4946875 15.81921875 -15.234375 15.2109375 C-13.8550269 12.74033299 -12.42482424 11.42049443 -10.25 9.625 C-6.6385246 6.5736987 -3.30090396 3.38342656 0 0 Z " fill="#0DC260" transform="translate(1456,953)"/>
<path d="M0 0 C4.82783324 2.15560327 8.0018426 5.67180855 11.6875 9.375 C12.72100586 10.38433594 12.72100586 10.38433594 13.77539062 11.4140625 C14.75862305 12.39632812 14.75862305 12.39632812 15.76171875 13.3984375 C16.35944092 13.99317871 16.95716309 14.58791992 17.57299805 15.20068359 C19.11683706 17.14732063 19.59286755 18.57190081 20 21 C15.09312847 17.0060348 10.55729437 12.6959047 6.0625 8.25 C5.47057861 7.67096924 4.87865723 7.09193848 4.26879883 6.49536133 C2.80590875 5.03589071 1.39785485 3.52187506 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-3.17703948 6.83444132 -8.40280876 12.56478535 -14 18 C-14.66 17.67 -15.32 17.34 -16 17 C-10.94647258 11.03651266 -5.58288259 5.46894621 0 0 Z " fill="#0DC260" transform="translate(300,954)"/>
<path d="M0 0 C5.48366593 2.02258932 9.90145405 5.13740049 14.6875 8.4375 C15.9878418 9.31631836 15.9878418 9.31631836 17.31445312 10.21289062 C18.14267578 10.78072266 18.97089844 11.34855469 19.82421875 11.93359375 C20.95476685 12.7078772 20.95476685 12.7078772 22.1081543 13.49780273 C24 15 24 15 26 18 C22.36210749 16.6800567 19.44577388 15.07570775 16.3125 12.8125 C11.89277787 9.64038712 7.42860768 6.54493223 2.93359375 3.48046875 C1 2 1 2 0 0 Z " fill="#0DC260" transform="translate(802,1737)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.32195312 1.4846875 0.64390625 1.969375 -0.0546875 2.46875 C-6.5266874 7.13002417 -12.8194913 11.95906449 -19 17 C-19.66 16.67 -20.32 16.34 -21 16 C-14.46357242 9.79369503 -7.594442 4.83165853 0 0 Z " fill="#0DC260" transform="translate(1559,871)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.48657473 5.28497559 -1.97988554 7.32947939 -3.6875 9.4375 C-4.13544922 10.01048828 -4.58339844 10.58347656 -5.04492188 11.17382812 C-7.52724234 14.31376478 -10.09714142 17.2331067 -13 20 C-13 15.81198866 -10.69900914 13.68878746 -8.1875 10.5625 C-7.28506413 9.41804138 -6.38271824 8.27351181 -5.48046875 7.12890625 C-4.66191406 6.09636719 -3.84335938 5.06382813 -3 4 C-1.99415118 2.6710734 -0.99102203 1.34001982 0 0 Z " fill="#0DC260" transform="translate(1686,1080)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.83333333 2.02083333 -0.33333333 3.04166667 -1.5 4.0625 C-2.22574219 4.69800781 -2.95148438 5.33351563 -3.69921875 5.98828125 C-5.19987905 7.30040359 -6.70239882 8.61040322 -8.20703125 9.91796875 C-8.90183594 10.52253906 -9.59664062 11.12710938 -10.3125 11.75 C-10.94800781 12.30171875 -11.58351563 12.8534375 -12.23828125 13.421875 C-13.88505175 14.89703084 -15.45376207 16.42045848 -17 18 C-17.66 17.67 -18.32 17.34 -19 17 C-17.33333333 15.33333333 -15.66666667 13.66666667 -14 12 C-13.236875 11.195625 -12.47375 10.39125 -11.6875 9.5625 C-8.83906474 6.8465501 -5.84703925 4.5500963 -2.671875 2.234375 C-1.05529654 1.10491666 -1.05529654 1.10491666 0 0 Z " fill="#0DC260" transform="translate(1493,922)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.0390625 4.25 -0.0390625 4.25 -1.625 7 C-4.24920071 11.61518362 -6.6099927 16.27744115 -8.82421875 21.1015625 C-10 23 -10 23 -13 24 C-11.20469881 18.95263894 -8.55008635 14.40609448 -5.9375 9.75 C-5.47794922 8.92242188 -5.01839844 8.09484375 -4.54492188 7.2421875 C-1.13705937 1.13705937 -1.13705937 1.13705937 0 0 Z " fill="#0DC260" transform="translate(1385,1523)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.60770997 3.73202093 -0.78900556 5.46048484 -2.1875 7.1875 C-2.96480469 8.15042969 -3.74210937 9.11335938 -4.54296875 10.10546875 C-6.91808927 12.90350421 -9.37082777 15.4455467 -12 18 C-10.46906512 13.32800909 -7.89242605 9.97829995 -4.875 6.1875 C-4.40707031 5.59001953 -3.93914062 4.99253906 -3.45703125 4.37695312 C-2.30994435 2.91383208 -1.15568766 1.45633703 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C3.27971932 3.02743322 5.83952114 6.38308979 8.47265625 9.9609375 C10.54799611 12.73159583 12.75836664 15.36278428 15 18 C10.65299804 16.63444965 8.60531597 14.81529698 5.8125 11.25 C5.13832031 10.40953125 4.46414063 9.5690625 3.76953125 8.703125 C1.9116764 5.86507741 0.92661416 3.25027735 0 0 Z " fill="#0DC260" transform="translate(763,1703)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945312 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C11.34 10.66 10.68 11.32 10 12 C8.32737283 10.38113585 6.66204463 8.7547271 5 7.125 C4.071875 6.22007812 3.14375 5.31515625 2.1875 4.3828125 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1709,915)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945313 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C8.28053558 10 7.59485764 9.11128458 4.875 6.6875 C4.17117188 6.07261719 3.46734375 5.45773437 2.7421875 4.82421875 C1 3 1 3 0 0 Z " fill="#0DC260" transform="translate(896,1589)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.30368347 4.68996005 -1.64444707 6.35135455 -3 8 C-4.44399479 10.6157212 -5.73708895 13.29280238 -7 16 C-7.67578125 14.328125 -7.67578125 14.328125 -8 12 C-6.85546875 9.421875 -6.85546875 9.421875 -5.1875 6.75 C-4.64480469 5.85796875 -4.10210938 4.9659375 -3.54296875 4.046875 C-3.03378906 3.37140625 -2.52460937 2.6959375 -2 2 C-1.34 2 -0.68 2 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1440,968)"/>
<path d="M0 0 C-1.38188453 3.21043882 -2.92421903 5.04936365 -5.625 7.25 C-6.57246094 8.03117188 -6.57246094 8.03117188 -7.5390625 8.828125 C-8.02117187 9.21484375 -8.50328125 9.6015625 -9 10 C-9 7 -9 7 -7.5390625 5.17578125 C-6.90742188 4.56089844 -6.27578125 3.94601562 -5.625 3.3125 C-4.68527344 2.37857422 -4.68527344 2.37857422 -3.7265625 1.42578125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C3.21043882 1.38188453 5.04936365 2.92421903 7.25 5.625 C8.03117187 6.57246094 8.03117187 6.57246094 8.828125 7.5390625 C9.40820312 8.26222656 9.40820312 8.26222656 10 9 C7 9 7 9 5.17578125 7.5390625 C4.56089844 6.90742187 3.94601562 6.27578125 3.3125 5.625 C2.68988281 4.99851562 2.06726562 4.37203125 1.42578125 3.7265625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1700,906)"/>
<path d="M0 0 C7.91607732 6.31117397 7.91607732 6.31117397 10 11 C9.67 11.66 9.34 12.32 9 13 C7.4941255 11.21326795 5.9954515 9.42046492 4.5 7.625 C3.6646875 6.62726563 2.829375 5.62953125 1.96875 4.6015625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(426,1167)"/>
<path d="M0 0 C0 3.80205426 -1.2000969 5.11156561 -3.375 8.1875 C-4.00148438 9.08855469 -4.62796875 9.98960938 -5.2734375 10.91796875 C-6.12808594 11.94857422 -6.12808594 11.94857422 -7 13 C-7.66 13 -8.32 13 -9 13 C-7.47987323 7.59510481 -3.72614782 4.01507372 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C4.20240011 3.71750779 6.99782679 8.31660979 10 13 C6.63834194 11.58956521 4.90494768 9.98473966 2.75 7.0625 C2.22921875 6.37285156 1.7084375 5.68320313 1.171875 4.97265625 C0 3 0 3 0 0 Z " fill="#0DC260" transform="translate(416,1153)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.21255542 4.22997426 -6.36291061 7.39163722 -11 10 C-9.54144353 6.31353859 -7.69770955 4.83856029 -4.375 2.75 C-3.55773437 2.22921875 -2.74046875 1.7084375 -1.8984375 1.171875 C-1.27195312 0.78515625 -0.64546875 0.3984375 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C1 3 1 3 -0.21484375 5.69921875 C-0.78332031 6.68535156 -1.35179687 7.67148438 -1.9375 8.6875 C-2.50339844 9.68136719 -3.06929687 10.67523437 -3.65234375 11.69921875 C-4.31943359 12.83810547 -4.31943359 12.83810547 -5 14 C-5.66 14 -6.32 14 -7 14 C-4.66666667 9.33333333 -2.33333333 4.66666667 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.11678083 3.6721852 -1.24366352 5.33762803 -2.375 7 C-3.00148438 7.928125 -3.62796875 8.85625 -4.2734375 9.8125 C-4.84320312 10.534375 -5.41296875 11.25625 -6 12 C-6.66 12 -7.32 12 -8 12 C-6.59023295 8.96147295 -4.91129772 6.4060405 -2.875 3.75 C-2.06675781 2.69039062 -2.06675781 2.69039062 -1.2421875 1.609375 C-0.83226562 1.07828125 -0.42234375 0.5471875 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C4.98012761 1.50912958 8.24259942 4.55661849 12 8 C11.01 8.33 10.02 8.66 9 9 C7.49704815 7.69088122 5.99770689 6.37761608 4.5 5.0625 C3.6646875 4.33160156 2.829375 3.60070312 1.96875 2.84765625 C1.3190625 2.23792969 0.669375 1.62820313 0 1 C0 0.67 0 0.34 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0 3.58912412 -0.66436554 4.10857029 -3 6.6875 C-3.556875 7.31011719 -4.11375 7.93273438 -4.6875 8.57421875 C-5.120625 9.04472656 -5.55375 9.51523438 -6 10 C-6.33 9.01 -6.66 8.02 -7 7 C-4.69 4.69 -2.38 2.38 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.14453125 5.0078125 -0.14453125 5.0078125 -1.8125 7.125 C-2.62654297 8.18074219 -2.62654297 8.18074219 -3.45703125 9.2578125 C-5 11 -5 11 -7 12 C-5.62567077 7.99153975 -3.7110562 5.23577676 -1 2 C-0.67 1.34 -0.34 0.68 0 0 Z " fill="#0DC260" transform="translate(1653,1123)"/>
<path d="M0 0 C3.36179774 1.44077046 5.59156268 3.24750021 8 6 C8 6.66 8 7.32 8 8 C4.63820226 6.55922954 2.40843732 4.75249979 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1755,963)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-5.11389522 7.70387244 -5.11389522 7.70387244 -10 8 C-6.97727468 4.74475735 -3.74281699 2.38179263 0 0 Z " fill="#0DC260" transform="translate(1181,1779)"/>
<path d="M0 0 C-1.49097658 3.7952131 -3.75700849 5.61042731 -7 8 C-7.66 7.67 -8.32 7.34 -9 7 C-7.88121617 5.82737096 -6.75476949 4.66204862 -5.625 3.5 C-4.68527344 2.52546875 -4.68527344 2.52546875 -3.7265625 1.53125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(1273,1717)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C-1.3 4.31 -4.6 6.62 -8 9 C-8.66 8.67 -9.32 8.34 -10 8 C-6.7 5.36 -3.4 2.72 0 0 Z " fill="#0DC260" transform="translate(1144,1595)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.87970983 2.48273699 -0.24638618 3.96108886 -1.375 5.4375 C-2.00148438 6.26121094 -2.62796875 7.08492187 -3.2734375 7.93359375 C-5 10 -5 10 -7 11 C-5.5140084 6.40693504 -3.14985318 3.56430755 0 0 Z " fill="#0DC260" transform="translate(1629,1156)"/>
<path d="M0 0 C3.7952131 1.49097658 5.61042731 3.75700849 8 7 C5 7 5 7 2.3125 4.625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C1.17539996 0.92652701 2.34010577 1.86663387 3.5 2.8125 C4.1496875 3.33457031 4.799375 3.85664062 5.46875 4.39453125 C7 6 7 6 7 9 C3.26115668 6.34345343 1.35021826 4.41889613 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.02 4.31 -1.96 6.62 -4 9 C-4.33 8.34 -4.66 7.68 -5 7 C-3.35 4.69 -1.7 2.38 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C-1.39332574 3.36720387 -2.9789286 4.9859524 -6 7 C-6 4 -6 4 -4.125 1.8125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(334,920)"/>
</svg>

Before

Width:  |  Height:  |  Size: 370 B

After

Width:  |  Height:  |  Size: 92 KiB

+56 -3
View File
@@ -1,4 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2 L22 7 L22 17 L12 22 L2 17 L2 7 Z" />
<path d="M7 10 L9.5 14 L12 10 L14.5 14 L17 10" />
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="2048" height="2048">
<path d="M0 0 C1.43859375 -0.00386719 1.43859375 -0.00386719 2.90625 -0.0078125 C5.5 0.125 5.5 0.125 8.5 1.125 C10.07494679 1.21669387 11.65351919 1.25137572 13.23113275 1.25215852 C14.21223816 1.25507056 15.19334358 1.25798259 16.20417947 1.26098287 C17.82819537 1.25816256 17.82819537 1.25816256 19.48501968 1.25528526 C20.63616652 1.25722869 21.78731336 1.25917212 22.97334343 1.26117444 C26.18790327 1.26559368 29.40242792 1.26551071 32.61698911 1.26360132 C36.10693665 1.26263044 39.59687675 1.26745584 43.08682132 1.27158034 C49.20990348 1.27802579 55.33297881 1.2807976 61.45606422 1.28120613 C70.56131082 1.28184984 79.66654691 1.28823542 88.77178995 1.29595293 C103.14813112 1.30804145 117.52447181 1.31669674 131.90081661 1.32299107 C154.72058471 1.33301518 177.54033782 1.35226383 200.36009693 1.37453346 C209.13518953 1.38306462 217.91028239 1.39133059 226.68537521 1.39963722 C227.66035547 1.40056223 228.63533572 1.40148724 229.63986083 1.40244028 C252.85870126 1.42444049 276.07754337 1.44422712 299.29638672 1.46289062 C300.31261062 1.4637103 301.32883452 1.46452998 302.37585309 1.4653745 C326.08672853 1.48446028 349.79760389 1.50142152 373.50848389 1.51373291 C374.52825771 1.51426258 375.54803154 1.51479225 376.5987076 1.51533796 C384.81851069 1.51958956 393.03831381 1.52376588 401.25811695 1.52792276 C435.12980914 1.54511112 469.00148086 1.57231006 502.87315546 1.61108314 C507.65434625 1.61654521 512.43553718 1.62187815 517.21672821 1.62712479 C518.62824923 1.62867636 518.62824923 1.62867636 520.06828583 1.63025927 C535.22952948 1.64660069 550.39075882 1.65211397 565.55201044 1.65342245 C580.78324492 1.65492508 596.01444047 1.6670549 611.24565777 1.69017886 C620.30022251 1.70358381 629.35470229 1.70856296 638.40927478 1.7016325 C644.45363612 1.69782031 650.497922 1.7048069 656.54226363 1.72064828 C659.98877247 1.72936664 663.4351068 1.73330374 666.88161829 1.72407441 C670.59179392 1.71663549 674.30147582 1.72747849 678.01161575 1.74303246 C679.08492836 1.73646991 680.15824097 1.72990737 681.2640782 1.72314596 C687.16414252 1.77028764 691.25210961 2.40563744 696.5 5.125 C699.01036535 5.9108535 701.53016035 6.59954783 704.0703125 7.28125 C706.5 8.125 706.5 8.125 708.81640625 9.55078125 C712.15660838 11.51017202 715.65183927 12.6206182 719.3125 13.8125 C725.12314078 15.78005859 730.57365124 18.01662951 736 20.875 C743.91548995 25.03164703 752.13060775 28.29606801 760.45703125 31.53613281 C767.24833937 34.18465636 773.88894678 37.05565422 780.5 40.125 C781.62792969 40.62644531 782.75585938 41.12789063 783.91796875 41.64453125 C789.87544004 44.42580487 794.18929719 47.33005411 798.62890625 52.17578125 C801.08514877 54.73458087 803.83225627 56.69473172 806.69921875 58.765625 C809.20702548 60.65871988 811.3078776 62.87807454 813.5 65.125 C815.44546571 66.87634115 817.41886327 68.59202216 819.3984375 70.3046875 C820.76539079 71.48870281 822.12521267 72.68101917 823.4765625 73.8828125 C827.55869277 77.50956569 831.7547855 80.91687025 836.08203125 84.24609375 C843.81041205 90.25150759 851.22731444 96.579583 858.5 103.125 C862.79301203 106.96166823 867.14571406 110.64678818 871.6875 114.1875 C875.54211521 117.23464994 878.45427389 120.29608718 881.5 124.125 C883.69250727 126.02122251 885.95622437 127.73591916 888.3125 129.421875 C892.8061002 132.68675639 896.64337693 136.21058322 900.5078125 140.1953125 C902.37665424 142.00552391 904.25777473 143.49498445 906.375 145 C909.75743286 147.42739299 912.59207175 150.14592977 915.5 153.125 C918.98022329 156.68492306 922.46095715 159.74889797 926.50390625 162.63671875 C930.39058911 165.53461732 933.90514203 168.87823568 937.5 172.125 C938.83079361 173.29456285 940.1640428 174.46133886 941.5 175.625 C945.11855573 178.78405659 948.70954679 181.97304518 952.29296875 185.171875 C953.66010228 186.38172768 955.03611085 187.5817273 956.42578125 188.765625 C960.74873375 192.45311243 964.90660118 196.31083127 969 200.25 C969.54116455 200.75305664 970.0823291 201.25611328 970.63989258 201.77441406 C972.99660725 204.07990406 974.40476361 205.5678671 974.96875 208.8671875 C974.5 211.125 974.5 211.125 972.5 213.125 C970.61562687 213.85104698 968.70207313 214.50219769 966.77734375 215.11328125 C965.60856689 215.48694824 964.43979004 215.86061523 963.2355957 216.24560547 C961.98222412 216.63893066 960.72885254 217.03225586 959.4375 217.4375 C958.1381504 217.85006252 956.83891587 218.26298758 955.53979492 218.67626953 C948.5355565 220.89675968 941.51300334 223.022592 934.44506836 225.03051758 C925.80854358 227.53971466 917.31020977 230.50140017 908.78790283 233.3694458 C900.95847523 236.00276091 893.1395024 238.63053102 885.1875 240.875 C878.27824501 242.83179209 871.55683625 245.19016733 864.79760742 247.61035156 C859.89923627 249.34437211 855.03775758 250.85190074 850 252.125 C834.43818465 256.15515457 821.00057835 260.7909593 808.5 271.125 C807.82066406 271.68316406 807.14132812 272.24132812 806.44140625 272.81640625 C805.34654654 273.74438203 804.26232429 274.68511918 803.19140625 275Line truncated
<path d="M0 0 C1.87410553 -0.02882263 1.87410553 -0.02882263 3.78607178 -0.05822754 C5.15066794 -0.06793431 6.51527271 -0.0764893 7.87988281 -0.08398438 C8.57336067 -0.08963913 9.26683853 -0.09529388 9.98133087 -0.10112 C13.66318779 -0.13109726 17.34488861 -0.14955102 21.02685547 -0.15820312 C24.04330478 -0.16692515 27.05859457 -0.19451452 30.07470703 -0.24023438 C62.05878142 -0.71603308 62.05878142 -0.71603308 74.83300781 6.32226562 C76.23824707 7.05388916 76.23824707 7.05388916 77.671875 7.80029297 C84.94627824 11.73996458 91.37540913 17.1855858 97.83300781 22.32226562 C99.16912109 23.381875 99.16912109 23.381875 100.53222656 24.46289062 C102.97193019 26.40852554 105.40246586 28.36520587 107.83300781 30.32226562 C108.68894531 31.00289062 109.54488281 31.68351563 110.42675781 32.38476562 C114.07474911 35.28557799 117.70690062 38.18252129 121.20800781 41.25976562 C124.22123139 43.87688469 127.37956066 46.25482674 130.58300781 48.63476562 C139.60741948 55.34377755 148.26891224 62.50597841 156.68457031 69.96289062 C161.16621103 73.92673221 165.76834253 77.69602372 170.45410156 81.41601562 C173.06943739 83.51171987 175.62630974 85.66038343 178.15332031 87.86132812 C179.26285929 88.826369 180.38259248 89.77982681 181.51269531 90.72070312 C203.40427145 109.22988982 203.40427145 109.22988982 207.83300781 121.32226562 C208.66275 123.30294052 209.49627508 125.28203372 210.33300781 127.25976562 C210.95755859 128.7834375 210.95755859 128.7834375 211.59472656 130.33789062 C214.15847576 136.51676882 217.00177331 142.56655147 219.85644531 148.61523438 C220.21311279 149.37102783 220.56978027 150.12682129 220.93725586 150.90551758 C221.64534326 152.40356049 222.355073 153.9008285 223.06665039 155.3972168 C227.83300781 165.4610834 227.83300781 165.4610834 227.83300781 170.32226562 C228.49300781 170.32226562 229.15300781 170.32226562 229.83300781 170.32226562 C230.22488281 171.41539062 230.61675781 172.50851562 231.02050781 173.63476562 C232.27815493 177.00030017 233.69377481 180.25201513 235.20800781 183.50976562 C237.60158636 188.67069475 239.60270713 193.9264454 241.52441406 199.27929688 C242.75369103 202.39742165 242.75369103 202.39742165 244.77832031 205.20898438 C247.13673802 208.7824804 248.60778549 212.34747542 250.14550781 216.32226562 C252.28246549 221.68767498 254.54076046 226.87949172 257.20800781 232.00976562 C260.84932475 239.07820438 263.80178067 246.38143656 266.72509766 253.7722168 C268.49135184 258.20522266 270.302487 262.26333909 272.83300781 266.32226562 C273.60406487 268.1804314 274.32999022 270.05769041 275.02050781 271.94726562 C279.63140189 284.18280082 284.607226 296.26409502 290.59863281 307.89257812 C292.16373794 310.97325973 293.47925323 314.1438853 294.83300781 317.32226562 C295.61745301 318.88840358 296.40987243 320.45055997 297.20800781 322.00976562 C299.58916087 326.70790894 301.59351132 331.51049921 303.58300781 336.38476562 C304.73625522 339.09489704 305.98949153 341.70240887 307.33300781 344.32226562 C310.16255909 349.85757531 312.49369373 355.56622466 314.83300781 361.32226562 C317.99874712 369.05833847 321.32809375 376.7069447 324.75024414 384.33203125 C327.05552171 389.49585301 329.22450609 394.70052878 331.33300781 399.94726562 C334.21213545 407.08170247 337.53898567 413.92075478 341.03222656 420.77148438 C346.83300781 432.20946736 346.83300781 432.20946736 346.83300781 436.32226562 C347.49300781 436.32226562 348.15300781 436.32226562 348.83300781 436.32226562 C349.1359375 437.1446875 349.43886719 437.96710938 349.75097656 438.81445312 C351.73651914 444.10516043 353.72451414 449.30402066 356.33300781 454.32226562 C358.82082889 459.11909563 360.69649102 464.06501504 362.59472656 469.11914062 C364.05383396 472.89348783 365.69874287 476.54824977 367.40332031 480.21679688 C368.48238788 482.56067314 369.53787919 484.90920718 370.57519531 487.27148438 C374.24836792 495.63261176 378.04976242 503.91033614 382.02050781 512.13476562 C385.24537657 518.82085247 388.14633604 525.47021049 390.70410156 532.43945312 C392.26792911 536.4328951 394.22040473 540.18335657 396.18066406 543.99414062 C398.1034708 547.86702796 399.84895607 551.79971734 401.58300781 555.75976562 C404.56190043 562.55201713 407.68207529 569.26288869 410.89550781 575.94726562 C414.42834028 583.30627766 417.80799145 590.70768437 421.04394531 598.20117188 C423.15888208 603.09453129 425.33705032 607.95917119 427.52050781 612.82226562 C427.88926025 613.64734619 428.2580127 614.47242676 428.63793945 615.32250977 C430.34586501 619.12111197 432.09530728 622.88008087 433.98535156 626.59179688 C435.46163903 629.50950745 436.67072187 632.40284726 437.70800781 635.50976562 C440.00105327 641.98164295 442.88313053 648.12922132 445.83300781 654.32226562 C446.97919244 656.7373483 448.12466916 659.15276519 449.26977539 661.56835938 C450.04006522 663.19155487 450.81194045 664.81399932 451.58569336 666.43554688 C454.08878497 671.69420811 456.48593201 676.99234018 458.83300781 682.32226562 C461.99550894 689.41193233 465.23699803 696.44086054 468.83Line truncated
<path d="M0 0 C5.44333286 1.53093737 8.92825297 5.29018604 13 9 C14.35338261 10.14675931 15.70753684 11.29260864 17.0625 12.4375 C21.64462627 16.44686048 25.45821971 20.99400134 29.38046265 25.63258362 C34.2136011 31.25757669 39.38333733 36.48054236 44.66015625 41.6875 C46.04798169 43.06591387 47.43580107 44.4443339 48.82327175 45.82310486 C52.20679048 49.18389109 55.59581215 52.53911093 58.98754883 55.89160156 C60.90240519 57.78472355 62.81446848 59.68059109 64.72373962 61.5793457 C66.51027671 63.35563876 68.3008835 65.1278513 70.09620667 66.89526367 C74.35703946 71.1384933 78.20739247 75.38633314 81.71757507 80.269104 C83.45492247 82.61401137 85.42886308 84.62111363 87.5234375 86.6484375 C88.31621094 87.42574219 89.10898438 88.20304688 89.92578125 89.00390625 C90.73402344 89.78636719 91.54226563 90.56882812 92.375 91.375 C94.01229839 92.96152945 95.64536337 94.55244365 97.2734375 96.1484375 C97.98935059 96.84114746 98.70526367 97.53385742 99.44287109 98.24755859 C101 100 101 100 101 102 C97.76847648 100.57784217 95.59614267 98.85315081 93.1015625 96.3671875 C92.01101563 95.28050781 92.01101563 95.28050781 90.8984375 94.171875 C90.14820313 93.41390625 89.39796875 92.6559375 88.625 91.875 C87.8825 91.14023437 87.14 90.40546875 86.375 89.6484375 C85.64539062 88.91625 84.91578125 88.1840625 84.1640625 87.4296875 C83.50873535 86.77210449 82.8534082 86.11452148 82.17822266 85.43701172 C80.40676903 83.45509622 78.90545865 81.50615912 77.36254883 79.35375977 C73.42786725 74.03908037 68.74419397 69.53326462 64.03515625 64.91015625 C63.07341827 63.95725701 62.11228386 63.00374827 61.15171814 62.04966736 C57.61754348 58.54196208 54.07249327 55.04531716 50.52764893 51.54840088 C47.52256879 48.58311201 44.5218497 45.61353187 41.52651787 42.63839531 C40.1377354 41.26236732 38.74278986 39.89256827 37.34767151 38.52296448 C32.68049146 33.8915949 28.39133942 29.20890356 24.46846008 23.92750549 C22.24689754 21.01147525 19.73765741 18.43878566 17.125 15.875 C16.61469238 15.36783447 16.10438477 14.86066895 15.57861328 14.33813477 C11.86265546 10.70169682 7.96638614 7.44283837 3.7421875 4.40234375 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.99 0.495 0.99 0.495 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-10.22159357 9.88886962 -20.26620359 19.24636214 -28.94433594 29.45092773 C-33.33817211 34.48296797 -38.06905727 39.16680262 -42.81651497 43.8611145 C-44.44720722 45.47414979 -46.07410308 47.09093049 -47.70005798 48.70874023 C-52.31793061 53.30238803 -56.94152361 57.8902459 -61.56958008 62.47363281 C-64.41544977 65.29255287 -67.25629051 68.11646317 -70.09420586 70.94338989 C-71.16746948 72.0104976 -72.24261966 73.0757117 -73.31978035 74.1388855 C-78.51758323 79.26974787 -83.59728576 84.33132654 -87.79176331 90.34082031 C-89.85752511 93.1775741 -92.35567767 95.56967547 -94.875 98 C-95.37257813 98.48855469 -95.87015625 98.97710938 -96.3828125 99.48046875 C-97.58386954 100.65842854 -98.79123559 101.82995047 -100 103 C-100.66 102.67 -101.32 102.34 -102 102 C-97.66938005 96.88958996 -93.15590527 92.09370778 -88.30859375 87.46875 C-86.43361103 85.46369234 -84.90438774 83.5337759 -83.31016541 81.31732178 C-80.10058647 77.01114969 -76.52866446 73.23952404 -72.72875977 69.45410156 C-72.027117 68.74734787 -71.32547424 68.04059418 -70.60256958 67.31242371 C-68.30394979 65.00001179 -65.99808728 62.69499372 -63.69140625 60.390625 C-62.07985421 58.77518165 -60.46852455 57.15951643 -58.85740662 55.54364014 C-55.48930414 52.16809876 -52.11738238 48.79642904 -48.74291992 45.42724609 C-44.42597845 41.11611025 -40.12053683 36.79368847 -35.81810093 32.46808243 C-32.49728519 29.13251882 -29.16955123 25.80392492 -25.83979607 22.47728729 C-24.24948973 20.88646875 -22.66153521 19.29329543 -21.07602119 17.6977005 C-18.85800961 15.46731558 -16.6306167 13.2467285 -14.40063477 11.02832031 C-13.75262405 10.37266586 -13.10461334 9.71701141 -12.43696594 9.04148865 C-8.57529327 5.22384661 -4.92754094 2.33444496 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.625 5.34765625 -0.625 5.34765625 -3 8.0625 C-5.93698686 11.51830943 -8.75427783 14.94221196 -11.3125 18.6875 C-15.29868574 24.50145294 -19.54276155 30.1095513 -23.7890625 35.734375 C-25.9890044 38.64872406 -28.16907394 41.57660234 -30.3359375 44.515625 C-30.87645752 45.24571777 -31.41697754 45.97581055 -31.97387695 46.72802734 C-33.01261099 48.13184279 -34.04776171 49.53831861 -35.07885742 50.94775391 C-35.54912354 51.58116699 -36.01938965 52.21458008 -36.50390625 52.8671875 C-36.91455322 53.42519043 -37.3252002 53.98319336 -37.74829102 54.55810547 C-39 56 -39 56 -42 58 C-40.57903924 53.77531559 -38.50867165 50.93955733 -35.625 47.5625 C-32.48959794 43.82298385 -29.66696013 40.08933887 -27 36 C-24.70129936 32.97299816 -22.34483765 29.99133556 -20 27 C-16.45233144 22.43871185 -13.16862732 17.77161076 -10 12.9375 C-6.94299635 8.29908484 -3.73419762 4.10761738 0 0 Z " fill="#0DC260" transform="translate(1664,1109)"/>
<path d="M0 0 C0.495 1.485 0.495 1.485 1 3 C-0.34169662 5.05562693 -1.69564379 6.86486955 -3.25 8.75 C-4.18647751 9.92582536 -5.12131468 11.10295862 -6.0546875 12.28125 C-6.78703613 13.19970703 -6.78703613 13.19970703 -7.53417969 14.13671875 C-9.88398864 17.12368442 -12.1336178 20.18123735 -14.375 23.25 C-14.82472168 23.86528564 -15.27444336 24.48057129 -15.73779297 25.11450195 C-19.31788916 30.03099096 -22.85663624 34.97668341 -26.375 39.9375 C-26.86274902 40.62295898 -27.35049805 41.30841797 -27.85302734 42.01464844 C-31.07241726 46.57646529 -34.08918083 51.2356156 -37 56 C-37.33 55.34 -37.66 54.68 -38 54 C-36.55859375 51.2421875 -36.55859375 51.2421875 -34.4375 47.875 C-34.06689453 47.28533447 -33.69628906 46.69566895 -33.31445312 46.08813477 C-30.89736314 42.28455772 -28.3370912 38.65452968 -25.5703125 35.1015625 C-22.85128247 31.46266161 -20.41173412 27.63484565 -17.9296875 23.83203125 C-16.07017303 21.10298673 -14.086559 18.55771748 -12 16 C-11.03492127 14.73428156 -10.07612986 13.46373357 -9.125 12.1875 C-8.6196875 11.51074219 -8.114375 10.83398438 -7.59375 10.13671875 C-7.0678125 9.43160156 -6.541875 8.72648437 -6 8 C-4.87540898 6.49969335 -3.75042464 4.99968142 -2.625 3.5 C-2.12226562 2.8296875 -1.61953125 2.159375 -1.1015625 1.46875 C-0.73804688 0.9840625 -0.37453125 0.499375 0 0 Z " fill="#0DC260" transform="translate(1509,1315)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.53851563 1.32871094 1.07703125 1.65742187 0.6015625 1.99609375 C-11.17878346 10.5868994 -21.73310024 20.90322611 -31.1953125 31.97265625 C-34.61943288 35.81923304 -38.3225033 39.39755425 -42 43 C-42.66 42.34 -43.32 41.68 -44 41 C-38.86950975 35.79321757 -33.72711487 30.59841286 -28.57641602 25.41162109 C-26.82692975 23.64708236 -25.08014983 21.87985596 -23.33618164 20.10986328 C-20.82370575 17.5608501 -18.30153929 15.02177671 -15.77734375 12.484375 C-15.00414291 11.69569031 -14.23094208 10.90700562 -13.43431091 10.09442139 C-9.24303815 5.90186564 -5.4197086 2.47910486 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.19140625 1.328125 3.19140625 1.328125 4.5625 3.25 C5.09101562 3.97960938 5.61953125 4.70921875 6.1640625 5.4609375 C7.07285156 6.71777344 7.07285156 6.71777344 8 8 C9.47680111 9.96011784 10.95610817 11.91834936 12.4375 13.875 C18.89826433 22.51078117 24.95045701 31.36455683 30.875 40.375 C31.45926758 41.25607422 32.04353516 42.13714844 32.64550781 43.04492188 C33.19303711 43.88345703 33.74056641 44.72199219 34.3046875 45.5859375 C34.79952637 46.3392334 35.29436523 47.0925293 35.80419922 47.86865234 C36.96346212 49.93487634 37.55479394 51.68479735 38 54 C35.15497965 51.41843814 33.21663697 48.46505704 31.12109375 45.2578125 C30.36164909 44.10300467 29.60204015 42.94830486 28.84228516 41.79370117 C28.44906067 41.19351166 28.05583618 40.59332214 27.6506958 39.97494507 C21.70740437 30.91230022 15.74825198 21.92928068 8.9453125 13.48046875 C5.60068864 9.21573753 2.74542467 4.66722194 0 0 Z " fill="#0DC260" transform="translate(541,1321)"/>
<path d="M0 0 C0 3.95229679 -1.3349536 5.08305206 -3.75 8.1875 C-4.57984179 9.26530583 -5.40924597 10.34344869 -6.23828125 11.421875 C-6.68510254 11.99873047 -7.13192383 12.57558594 -7.59228516 13.16992188 C-9.56044812 15.72860199 -11.48925042 18.31593331 -13.41943359 20.90332031 C-15.93655042 24.27620829 -18.46798471 27.63828945 -21 31 C-21.73162354 31.97259766 -21.73162354 31.97259766 -22.47802734 32.96484375 C-23.85581766 34.79255338 -25.23931786 36.61576941 -26.625 38.4375 C-27.42164063 39.48808594 -28.21828125 40.53867188 -29.0390625 41.62109375 C-31 44 -31 44 -33 45 C-31.54990614 40.73547666 -29.41610759 37.70574079 -26.625 34.1875 C-25.72420879 33.04119019 -24.82451948 31.89401386 -23.92578125 30.74609375 C-23.21349365 29.83899658 -23.21349365 29.83899658 -22.48681641 28.91357422 C-19.88186953 25.56093487 -17.35080221 22.15319629 -14.8125 18.75 C-3.12797339 3.12797339 -3.12797339 3.12797339 0 0 Z " fill="#0DC260" transform="translate(1552,1259)"/>
<path d="M0 0 C0 3.99234494 -1.42869817 5.18478884 -3.875 8.3125 C-4.70984167 9.3946714 -5.54311699 10.47805258 -6.375 11.5625 C-7.02662109 12.40941406 -7.02662109 12.40941406 -7.69140625 13.2734375 C-9.81511979 16.07547148 -11.84355718 18.94324423 -13.875 21.8125 C-14.70666567 22.9794273 -15.53870363 24.14608935 -16.37109375 25.3125 C-17.73818886 27.22882336 -19.10368027 29.14620956 -20.46533203 31.06640625 C-21.94870966 33.15380256 -23.44208852 35.23371371 -24.9375 37.3125 C-25.39817871 37.96516846 -25.85885742 38.61783691 -26.33349609 39.2902832 C-29.65835146 43.88611715 -29.65835146 43.88611715 -33 45 C-31.72680443 42.30879389 -30.33905096 39.96461661 -28.53125 37.6015625 C-28.04744873 36.96420166 -27.56364746 36.32684082 -27.06518555 35.67016602 C-26.54867432 34.99526123 -26.03216309 34.32035645 -25.5 33.625 C-21.4806195 28.32587106 -17.52707318 22.99339628 -13.6875 17.5625 C-4.27091369 4.27091369 -4.27091369 4.27091369 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.48046875 1.87109375 3.48046875 1.87109375 5.1875 4.4375 C8.0928836 8.71118667 11.13543954 12.80960229 14.328125 16.87109375 C18.75370152 22.50646572 22.95481629 28.29953431 27.125 34.125 C27.54499268 34.71112061 27.96498535 35.29724121 28.39770508 35.90112305 C31.0041561 39.55551267 33.52854089 43.25294909 36 47 C33.02271967 45.69724211 31.31349963 44.49230891 29.40625 41.8671875 C28.93928711 41.23393555 28.47232422 40.60068359 27.99121094 39.94824219 C27.49911133 39.26407227 27.00701172 38.57990234 26.5 37.875 C25.43263379 36.41901996 24.36491534 34.9632981 23.296875 33.5078125 C22.75224609 32.76047852 22.20761719 32.01314453 21.64648438 31.24316406 C19.55403076 28.3924132 17.41574682 25.57804441 15.27636719 22.76245117 C0 2.62120122 0 2.62120122 0 0 Z " fill="#0DC260" transform="translate(390,1119)"/>
<path d="M0 0 C0.495 0.99 0.495 0.99 1 2 C0.46632813 2.70382812 -0.06734375 3.40765625 -0.6171875 4.1328125 C-4.7581594 9.62067492 -8.83803838 15.14026725 -12.8125 20.75 C-18.39183767 28.61304526 -24.17549805 36.31751802 -30 44 C-30.74121094 44.98226562 -31.48242188 45.96453125 -32.24609375 46.9765625 C-33.17615234 48.19472656 -33.17615234 48.19472656 -34.125 49.4375 C-34.64320312 50.11683594 -35.16140625 50.79617188 -35.6953125 51.49609375 C-37 53 -37 53 -39 54 C-37.73351701 51.32663783 -36.35872407 48.98783209 -34.56640625 46.63671875 C-33.84904297 45.68937866 -33.84904297 45.68937866 -33.1171875 44.72290039 C-32.60414062 44.05121826 -32.09109375 43.37953613 -31.5625 42.6875 C-30.46943898 41.24265112 -29.37700455 39.79732802 -28.28515625 38.3515625 C-27.73359863 37.62227539 -27.18204102 36.89298828 -26.61376953 36.14160156 C-24.22006805 32.96496776 -21.85383748 29.76875244 -19.5 26.5625 C-19.05994629 25.96308594 -18.61989258 25.36367188 -18.16650391 24.74609375 C-13.99517535 19.03748354 -9.92595062 13.25722305 -5.8828125 7.45727539 C-5.16544922 6.43234985 -5.16544922 6.43234985 -4.43359375 5.38671875 C-4.01134521 4.78045654 -3.58909668 4.17419434 -3.15405273 3.54956055 C-2 2 -2 2 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.77930427 4.98275356 -7.89432435 8.45606043 -13 12 C-13.7734375 12.5465625 -14.546875 13.093125 -15.34375 13.65625 C-21.62632327 18.09593511 -28.00931818 22.37453192 -34.42578125 26.6171875 C-36.59283051 28.0527361 -38.72836028 29.51214389 -40.85546875 31.0078125 C-42.04076172 31.83925781 -42.04076172 31.83925781 -43.25 32.6875 C-43.91515625 33.16574219 -44.5803125 33.64398437 -45.265625 34.13671875 C-47 35 -47 35 -50 34 C-49.05793701 33.37544922 -48.11587402 32.75089844 -47.14526367 32.10742188 C-43.59692322 29.75407453 -40.05073106 27.3975066 -36.50512695 25.04003906 C-34.98030604 24.02681139 -33.45493025 23.01441815 -31.92895508 22.00292969 C-23.89485818 16.67674795 -15.90926427 11.32892639 -8.16210938 5.58984375 C-5.49821709 3.63102865 -2.77354222 1.79905441 0 0 Z " fill="#0DC260" transform="translate(1262,1725)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.09192462 4.2293461 -1.23074255 6.31155714 -2.5 8.4375 C-2.87020264 9.06567627 -3.24040527 9.69385254 -3.62182617 10.34106445 C-4.38228515 11.62500065 -5.1468658 12.90650448 -5.91552734 14.18554688 C-6.86492959 15.77401097 -7.78821576 17.37802481 -8.70703125 18.984375 C-13.57277616 27.17682142 -20.59472291 36.9950649 -30 40 C-26.57368618 35.85235695 -23.05846555 32.10994854 -19.125 28.4375 C-14.17582261 23.56263458 -11.06901407 18.41845085 -7.828125 12.36328125 C-5.48374537 8.05022385 -2.808364 4.02106664 0 0 Z " fill="#0DC260" transform="translate(1294,1685)"/>
<path d="M0 0 C0 4.96076816 -3.70609257 7.52309772 -7 11 C-7.45020508 11.47743652 -7.90041016 11.95487305 -8.36425781 12.44677734 C-14.41125839 18.8162035 -20.3241597 24.5805768 -28 29 C-28.66 28.67 -29.32 28.34 -30 28 C-29.4013916 27.54431641 -28.8027832 27.08863281 -28.18603516 26.61914062 C-21.42258811 21.35504437 -15.37230867 15.61281239 -9.375 9.5 C-8.46621094 8.5821875 -7.55742188 7.664375 -6.62109375 6.71875 C-4.40935522 4.48373001 -2.20247028 2.2441473 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C1 3 1 3 0.06640625 5.20703125 C-0.67802734 6.49673828 -0.67802734 6.49673828 -1.4375 7.8125 C-2.27861328 9.28976562 -2.27861328 9.28976562 -3.13671875 10.796875 C-3.75160156 11.85390625 -4.36648438 12.9109375 -5 14 C-6.25086158 16.18700745 -7.50082204 18.37453047 -8.75 20.5625 C-9.07605225 21.13025146 -9.40210449 21.69800293 -9.73803711 22.28295898 C-14.24535052 30.13996979 -18.61485868 38.07439622 -23 46 C-23.99 46 -24.98 46 -26 46 C-25.63648438 45.40574219 -25.27296875 44.81148437 -24.8984375 44.19921875 C-21.66368637 38.86602651 -18.59435478 33.47330677 -15.6328125 27.984375 C-13.79819816 24.63115644 -11.90490468 21.31354341 -10 18 C-6.57917293 12.04668115 -3.25669739 6.04462774 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C4.65493075 3.27788227 7.42290802 7.10813577 10.5625 11.75 C15.25090056 18.55740994 20.09413207 25.20623775 25.16625977 31.73339844 C27.69700716 35.04114856 29.69728518 37.98457313 31 42 C26.95211837 38.15856771 23.62027498 34.04937522 20.3125 29.5625 C19.79429687 28.86600342 19.27609375 28.16950684 18.7421875 27.4519043 C14.86136976 22.21718881 11.04994532 16.93359846 7.2980957 11.60571289 C5.51005962 9.0729485 3.69085013 6.62467936 1.71875 4.23046875 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(284,976)"/>
<path d="M0 0 C6.18134869 5.10448822 11.79822878 10.68294942 17.4375 16.375 C18.35982422 17.30183594 19.28214844 18.22867187 20.23242188 19.18359375 C22.49058625 21.45345846 24.74636942 23.72563538 27 26 C19.96300327 26 13.4594101 16.60865459 8.625 11.875 C8.00584717 11.2773584 7.38669434 10.6797168 6.7487793 10.06396484 C3.58062768 6.91894479 1.24892948 4.41288415 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C-1.56282982 3.76603869 -3.9063475 6.13639151 -6.7890625 8.984375 C-7.25234955 9.44483215 -7.7156366 9.90528931 -8.19296265 10.37969971 C-9.66565898 11.84125078 -11.14517403 13.29567168 -12.625 14.75 C-13.62806322 15.74302611 -14.63067257 16.73651089 -15.6328125 17.73046875 C-18.08330835 20.15897941 -20.5399667 22.58114675 -23 25 C-23.33 24.01 -23.66 23.02 -24 22 C-20.90984779 18.86050859 -17.81325304 15.72756243 -14.71044922 12.60058594 C-13.65525491 11.5353174 -12.60186036 10.46826303 -11.55029297 9.39941406 C-10.04080273 7.86573784 -8.52501301 6.33854432 -7.0078125 4.8125 C-6.09660645 3.89082031 -5.18540039 2.96914063 -4.24658203 2.01953125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C0.94939453 0.95326172 0.94939453 0.95326172 1.91796875 1.92578125 C4.40684041 4.41640873 6.91556844 6.88636378 9.42578125 9.35546875 C11.05480558 10.96602641 12.68370884 12.57670653 14.3125 14.1875 C15.56643555 15.41629883 15.56643555 15.41629883 16.84570312 16.66992188 C17.63525391 17.45302734 18.42480469 18.23613281 19.23828125 19.04296875 C20.321698 20.11067505 20.321698 20.11067505 21.42700195 21.19995117 C23 23 23 23 23 25 C19.68545526 23.55480663 17.50259028 21.74845019 14.9609375 19.19140625 C14.21585938 18.44439453 13.47078125 17.69738281 12.703125 16.92773438 C11.93484375 16.14720703 11.1665625 15.36667969 10.375 14.5625 C9.59898438 13.78583984 8.82296875 13.00917969 8.0234375 12.20898438 C0 4.12286377 0 4.12286377 0 0 Z " fill="#0DC260" transform="translate(1740,946)"/>
<path d="M0 0 C5.44302277 1.53085015 8.92878538 5.2900022 13 9 C14.37403608 10.16780177 15.74901722 11.3344926 17.125 12.5 C20.81795255 15.71856141 23.90425351 19.20771054 27 23 C26.67 23.66 26.34 24.32 26 25 C25.59273682 24.58226318 25.18547363 24.16452637 24.76586914 23.73413086 C14.77635583 13.36838734 14.77635583 13.36838734 3.63671875 4.296875 C2 3 2 3 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.42032471 1.55349121 0.84064941 2.10698242 0.2434082 2.67724609 C-2.41374893 5.22949798 -5.0505307 7.80190193 -7.6875 10.375 C-8.59951172 11.24511719 -9.51152344 12.11523438 -10.45117188 13.01171875 C-16.07537506 18.5336637 -20.04369605 23.66599722 -23 31 C-24.14306641 27.32226562 -24.14306641 27.32226562 -22.85546875 24.421875 C-22.30503906 23.54015625 -21.75460937 22.6584375 -21.1875 21.75 C-20.37345703 20.41195312 -20.37345703 20.41195312 -19.54296875 19.046875 C-19.03378906 18.37140625 -18.52460937 17.6959375 -18 17 C-17.34 17 -16.68 17 -16 17 C-15.74734375 16.40960937 -15.4946875 15.81921875 -15.234375 15.2109375 C-13.8550269 12.74033299 -12.42482424 11.42049443 -10.25 9.625 C-6.6385246 6.5736987 -3.30090396 3.38342656 0 0 Z " fill="#0DC260" transform="translate(1456,953)"/>
<path d="M0 0 C4.82783324 2.15560327 8.0018426 5.67180855 11.6875 9.375 C12.72100586 10.38433594 12.72100586 10.38433594 13.77539062 11.4140625 C14.75862305 12.39632812 14.75862305 12.39632812 15.76171875 13.3984375 C16.35944092 13.99317871 16.95716309 14.58791992 17.57299805 15.20068359 C19.11683706 17.14732063 19.59286755 18.57190081 20 21 C15.09312847 17.0060348 10.55729437 12.6959047 6.0625 8.25 C5.47057861 7.67096924 4.87865723 7.09193848 4.26879883 6.49536133 C2.80590875 5.03589071 1.39785485 3.52187506 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-3.17703948 6.83444132 -8.40280876 12.56478535 -14 18 C-14.66 17.67 -15.32 17.34 -16 17 C-10.94647258 11.03651266 -5.58288259 5.46894621 0 0 Z " fill="#0DC260" transform="translate(300,954)"/>
<path d="M0 0 C5.48366593 2.02258932 9.90145405 5.13740049 14.6875 8.4375 C15.9878418 9.31631836 15.9878418 9.31631836 17.31445312 10.21289062 C18.14267578 10.78072266 18.97089844 11.34855469 19.82421875 11.93359375 C20.95476685 12.7078772 20.95476685 12.7078772 22.1081543 13.49780273 C24 15 24 15 26 18 C22.36210749 16.6800567 19.44577388 15.07570775 16.3125 12.8125 C11.89277787 9.64038712 7.42860768 6.54493223 2.93359375 3.48046875 C1 2 1 2 0 0 Z " fill="#0DC260" transform="translate(802,1737)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C1.32195312 1.4846875 0.64390625 1.969375 -0.0546875 2.46875 C-6.5266874 7.13002417 -12.8194913 11.95906449 -19 17 C-19.66 16.67 -20.32 16.34 -21 16 C-14.46357242 9.79369503 -7.594442 4.83165853 0 0 Z " fill="#0DC260" transform="translate(1559,871)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.48657473 5.28497559 -1.97988554 7.32947939 -3.6875 9.4375 C-4.13544922 10.01048828 -4.58339844 10.58347656 -5.04492188 11.17382812 C-7.52724234 14.31376478 -10.09714142 17.2331067 -13 20 C-13 15.81198866 -10.69900914 13.68878746 -8.1875 10.5625 C-7.28506413 9.41804138 -6.38271824 8.27351181 -5.48046875 7.12890625 C-4.66191406 6.09636719 -3.84335938 5.06382813 -3 4 C-1.99415118 2.6710734 -0.99102203 1.34001982 0 0 Z " fill="#0DC260" transform="translate(1686,1080)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.83333333 2.02083333 -0.33333333 3.04166667 -1.5 4.0625 C-2.22574219 4.69800781 -2.95148438 5.33351563 -3.69921875 5.98828125 C-5.19987905 7.30040359 -6.70239882 8.61040322 -8.20703125 9.91796875 C-8.90183594 10.52253906 -9.59664062 11.12710938 -10.3125 11.75 C-10.94800781 12.30171875 -11.58351563 12.8534375 -12.23828125 13.421875 C-13.88505175 14.89703084 -15.45376207 16.42045848 -17 18 C-17.66 17.67 -18.32 17.34 -19 17 C-17.33333333 15.33333333 -15.66666667 13.66666667 -14 12 C-13.236875 11.195625 -12.47375 10.39125 -11.6875 9.5625 C-8.83906474 6.8465501 -5.84703925 4.5500963 -2.671875 2.234375 C-1.05529654 1.10491666 -1.05529654 1.10491666 0 0 Z " fill="#0DC260" transform="translate(1493,922)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.0390625 4.25 -0.0390625 4.25 -1.625 7 C-4.24920071 11.61518362 -6.6099927 16.27744115 -8.82421875 21.1015625 C-10 23 -10 23 -13 24 C-11.20469881 18.95263894 -8.55008635 14.40609448 -5.9375 9.75 C-5.47794922 8.92242188 -5.01839844 8.09484375 -4.54492188 7.2421875 C-1.13705937 1.13705937 -1.13705937 1.13705937 0 0 Z " fill="#0DC260" transform="translate(1385,1523)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.60770997 3.73202093 -0.78900556 5.46048484 -2.1875 7.1875 C-2.96480469 8.15042969 -3.74210937 9.11335938 -4.54296875 10.10546875 C-6.91808927 12.90350421 -9.37082777 15.4455467 -12 18 C-10.46906512 13.32800909 -7.89242605 9.97829995 -4.875 6.1875 C-4.40707031 5.59001953 -3.93914062 4.99253906 -3.45703125 4.37695312 C-2.30994435 2.91383208 -1.15568766 1.45633703 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C3.27971932 3.02743322 5.83952114 6.38308979 8.47265625 9.9609375 C10.54799611 12.73159583 12.75836664 15.36278428 15 18 C10.65299804 16.63444965 8.60531597 14.81529698 5.8125 11.25 C5.13832031 10.40953125 4.46414063 9.5690625 3.76953125 8.703125 C1.9116764 5.86507741 0.92661416 3.25027735 0 0 Z " fill="#0DC260" transform="translate(763,1703)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945312 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C11.34 10.66 10.68 11.32 10 12 C8.32737283 10.38113585 6.66204463 8.7547271 5 7.125 C4.071875 6.22007812 3.14375 5.31515625 2.1875 4.3828125 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1709,915)"/>
<path d="M0 0 C3.45201639 1.47721422 5.64961936 3.43794001 8.25 6.125 C8.95640625 6.84945313 9.6628125 7.57390625 10.390625 8.3203125 C11.18726563 9.15175781 11.18726563 9.15175781 12 10 C8.28053558 10 7.59485764 9.11128458 4.875 6.6875 C4.17117188 6.07261719 3.46734375 5.45773437 2.7421875 4.82421875 C1 3 1 3 0 0 Z " fill="#0DC260" transform="translate(896,1589)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.30368347 4.68996005 -1.64444707 6.35135455 -3 8 C-4.44399479 10.6157212 -5.73708895 13.29280238 -7 16 C-7.67578125 14.328125 -7.67578125 14.328125 -8 12 C-6.85546875 9.421875 -6.85546875 9.421875 -5.1875 6.75 C-4.64480469 5.85796875 -4.10210938 4.9659375 -3.54296875 4.046875 C-3.03378906 3.37140625 -2.52460937 2.6959375 -2 2 C-1.34 2 -0.68 2 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1440,968)"/>
<path d="M0 0 C-1.38188453 3.21043882 -2.92421903 5.04936365 -5.625 7.25 C-6.57246094 8.03117188 -6.57246094 8.03117188 -7.5390625 8.828125 C-8.02117187 9.21484375 -8.50328125 9.6015625 -9 10 C-9 7 -9 7 -7.5390625 5.17578125 C-6.90742188 4.56089844 -6.27578125 3.94601562 -5.625 3.3125 C-4.68527344 2.37857422 -4.68527344 2.37857422 -3.7265625 1.42578125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(343,911)"/>
<path d="M0 0 C3.21043882 1.38188453 5.04936365 2.92421903 7.25 5.625 C8.03117187 6.57246094 8.03117187 6.57246094 8.828125 7.5390625 C9.40820312 8.26222656 9.40820312 8.26222656 10 9 C7 9 7 9 5.17578125 7.5390625 C4.56089844 6.90742187 3.94601562 6.27578125 3.3125 5.625 C2.68988281 4.99851562 2.06726562 4.37203125 1.42578125 3.7265625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1700,906)"/>
<path d="M0 0 C7.91607732 6.31117397 7.91607732 6.31117397 10 11 C9.67 11.66 9.34 12.32 9 13 C7.4941255 11.21326795 5.9954515 9.42046492 4.5 7.625 C3.6646875 6.62726563 2.829375 5.62953125 1.96875 4.6015625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(426,1167)"/>
<path d="M0 0 C0 3.80205426 -1.2000969 5.11156561 -3.375 8.1875 C-4.00148438 9.08855469 -4.62796875 9.98960938 -5.2734375 10.91796875 C-6.12808594 11.94857422 -6.12808594 11.94857422 -7 13 C-7.66 13 -8.32 13 -9 13 C-7.47987323 7.59510481 -3.72614782 4.01507372 0 0 Z " fill="#0DC260" transform="translate(1705,1055)"/>
<path d="M0 0 C4.20240011 3.71750779 6.99782679 8.31660979 10 13 C6.63834194 11.58956521 4.90494768 9.98473966 2.75 7.0625 C2.22921875 6.37285156 1.7084375 5.68320313 1.171875 4.97265625 C0 3 0 3 0 0 Z " fill="#0DC260" transform="translate(416,1153)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-2.21255542 4.22997426 -6.36291061 7.39163722 -11 10 C-9.54144353 6.31353859 -7.69770955 4.83856029 -4.375 2.75 C-3.55773437 2.22921875 -2.74046875 1.7084375 -1.8984375 1.171875 C-1.27195312 0.78515625 -0.64546875 0.3984375 0 0 Z " fill="#0DC260" transform="translate(386,869)"/>
<path d="M0 0 C1 3 1 3 -0.21484375 5.69921875 C-0.78332031 6.68535156 -1.35179687 7.67148438 -1.9375 8.6875 C-2.50339844 9.68136719 -3.06929687 10.67523437 -3.65234375 11.69921875 C-4.31943359 12.83810547 -4.31943359 12.83810547 -5 14 C-5.66 14 -6.32 14 -7 14 C-4.66666667 9.33333333 -2.33333333 4.66666667 0 0 Z " fill="#0DC260" transform="translate(1444,1417)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C-0.11678083 3.6721852 -1.24366352 5.33762803 -2.375 7 C-3.00148438 7.928125 -3.62796875 8.85625 -4.2734375 9.8125 C-4.84320312 10.534375 -5.41296875 11.25625 -6 12 C-6.66 12 -7.32 12 -8 12 C-6.59023295 8.96147295 -4.91129772 6.4060405 -2.875 3.75 C-2.06675781 2.69039062 -2.06675781 2.69039062 -1.2421875 1.609375 C-0.83226562 1.07828125 -0.42234375 0.5471875 0 0 Z " fill="#0DC260" transform="translate(1763,976)"/>
<path d="M0 0 C4.98012761 1.50912958 8.24259942 4.55661849 12 8 C11.01 8.33 10.02 8.66 9 9 C7.49704815 7.69088122 5.99770689 6.37761608 4.5 5.0625 C3.6646875 4.33160156 2.829375 3.60070312 1.96875 2.84765625 C1.3190625 2.23792969 0.669375 1.62820313 0 1 C0 0.67 0 0.34 0 0 Z " fill="#0DC260" transform="translate(1662,869)"/>
<path d="M0 0 C0 3.58912412 -0.66436554 4.10857029 -3 6.6875 C-3.556875 7.31011719 -4.11375 7.93273438 -4.6875 8.57421875 C-5.120625 9.04472656 -5.55375 9.51523438 -6 10 C-6.33 9.01 -6.66 8.02 -7 7 C-4.69 4.69 -2.38 2.38 0 0 Z " fill="#0DC260" transform="translate(1164,1575)"/>
<path d="M0 0 C0.33 0.99 0.66 1.98 1 3 C-0.14453125 5.0078125 -0.14453125 5.0078125 -1.8125 7.125 C-2.62654297 8.18074219 -2.62654297 8.18074219 -3.45703125 9.2578125 C-5 11 -5 11 -7 12 C-5.62567077 7.99153975 -3.7110562 5.23577676 -1 2 C-0.67 1.34 -0.34 0.68 0 0 Z " fill="#0DC260" transform="translate(1653,1123)"/>
<path d="M0 0 C3.36179774 1.44077046 5.59156268 3.24750021 8 6 C8 6.66 8 7.32 8 8 C4.63820226 6.55922954 2.40843732 4.75249979 0 2 C0 1.34 0 0.68 0 0 Z " fill="#0DC260" transform="translate(1755,963)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C-5.11389522 7.70387244 -5.11389522 7.70387244 -10 8 C-6.97727468 4.74475735 -3.74281699 2.38179263 0 0 Z " fill="#0DC260" transform="translate(1181,1779)"/>
<path d="M0 0 C-1.49097658 3.7952131 -3.75700849 5.61042731 -7 8 C-7.66 7.67 -8.32 7.34 -9 7 C-7.88121617 5.82737096 -6.75476949 4.66204862 -5.625 3.5 C-4.68527344 2.52546875 -4.68527344 2.52546875 -3.7265625 1.53125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(1273,1717)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C-1.3 4.31 -4.6 6.62 -8 9 C-8.66 8.67 -9.32 8.34 -10 8 C-6.7 5.36 -3.4 2.72 0 0 Z " fill="#0DC260" transform="translate(1144,1595)"/>
<path d="M0 0 C0.66 0.33 1.32 0.66 2 1 C0.87970983 2.48273699 -0.24638618 3.96108886 -1.375 5.4375 C-2.00148438 6.26121094 -2.62796875 7.08492187 -3.2734375 7.93359375 C-5 10 -5 10 -7 11 C-5.5140084 6.40693504 -3.14985318 3.56430755 0 0 Z " fill="#0DC260" transform="translate(1629,1156)"/>
<path d="M0 0 C3.7952131 1.49097658 5.61042731 3.75700849 8 7 C5 7 5 7 2.3125 4.625 C0 2 0 2 0 0 Z " fill="#0DC260" transform="translate(1720,926)"/>
<path d="M0 0 C1.17539996 0.92652701 2.34010577 1.86663387 3.5 2.8125 C4.1496875 3.33457031 4.799375 3.85664062 5.46875 4.39453125 C7 6 7 6 7 9 C3.26115668 6.34345343 1.35021826 4.41889613 0 0 Z " fill="#0DC260" transform="translate(881,1573)"/>
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.02 4.31 -1.96 6.62 -4 9 C-4.33 8.34 -4.66 7.68 -5 7 C-3.35 4.69 -1.7 2.38 0 0 Z " fill="#0DC260" transform="translate(1531,1286)"/>
<path d="M0 0 C-1.39332574 3.36720387 -2.9789286 4.9859524 -6 7 C-6 4 -6 4 -4.125 1.8125 C-2 0 -2 0 0 0 Z " fill="#0DC260" transform="translate(334,920)"/>
</svg>

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 92 KiB

+7 -7
View File
@@ -20,7 +20,7 @@
"workspaceContains:**/*.vpj",
"workspaceContains:**/*.vp"
],
"icon": "images/viper-icon.svg",
"icon": "images/viper-icon.png",
"main": "./dist/extension.js",
"contributes": {
"languages": [
@@ -100,33 +100,33 @@
"commands": [
{
"command": "viper.createProject",
"title": "Viper: Create Project",
"title": "Create Project",
"category": "Viper"
},
{
"command": "viper.selectToolchain",
"title": "Viper: Select Toolchain",
"title": "Select Toolchain",
"category": "Viper"
},
{
"command": "viper.showProjectInfo",
"title": "Viper: Show Project Info",
"title": "Show Project Info",
"category": "Viper"
},
{
"command": "viper.openSettings",
"title": "Viper: Open Settings",
"title": "Open Settings",
"category": "Viper"
},
{
"command": "viper.refreshView",
"title": "Viper: Refresh",
"title": "Refresh",
"category": "Viper",
"icon": "$(refresh)"
},
{
"command": "viper.openVpjAsJson",
"title": "Viper: Open .vpj as JSON",
"title": "Open .vpj as JSON",
"category": "Viper"
}
],
+1 -1
View File
@@ -1,2 +1,2 @@
// This is an entry-point for debugging the vipeye CLI
require('./out/packages/vipeye-internal/src/pyright').main();
require('./out/packages/vipeye-internal/src/viper').main();
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "pyright-internal",
"name": "vipeye-internal",
"version": "1.1.411",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pyright-internal",
"name": "vipeye-internal",
"version": "1.1.411",
"license": "MIT",
"dependencies": {
+1 -1
View File
@@ -15,7 +15,7 @@
"webpack:testserver:watch": "npm run clean && rspack build --config ./src/tests/lsp/rspack.testserver.config.js --mode development --watch",
"test": "npm run webpack:testserver && node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest --forceExit --testPathIgnorePatterns src/tests/benchmarks",
"test:norebuild": "node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest --forceExit --testPathIgnorePatterns src/tests/benchmarks",
"test:benchmark": "cross-env PYRIGHT_RUN_BENCHMARKS=1 node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest --forceExit --testTimeout=300000 --runInBand --detectOpenHandles src/tests/benchmarks",
"test:benchmark": "cross-env VIPER_RUN_BENCHMARKS=1 node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest --forceExit --testTimeout=300000 --runInBand --detectOpenHandles src/tests/benchmarks",
"test:coverage": "node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest --forceExit --testPathIgnorePatterns src/tests/benchmarks --reporters=jest-junit --reporters=default --coverage --coverageReporters=cobertura --coverageReporters=html --coverageReporters=json",
"test:imports": "node --max-old-space-size=8192 --expose-gc ./node_modules/jest/bin/jest importResolver.test --forceExit --runInBand"
},
@@ -368,7 +368,7 @@ export class Binder extends ParseTreeWalker {
// Single-underscore module-level names remain private even when __all__ uses an
// unsupported/computed form. Since every entry in _potentialPrivateSymbols already
// has an underscore prefix, shouldProcess always returns true here, preserving
// the behavior of upstream pyright test `Private3`.
// the behavior of upstream vipeye test `Private3`.
this._potentialPrivateSymbols.forEach((symbol, name) => {
if (shouldProcess(name) && !this._dunderAllNames?.some((sym) => sym === name)) {
symbol.setIsPrivateMember();
@@ -66,7 +66,7 @@ export function getFileLevelDirectives(
return curTokenLineOffset <= 1;
};
ruleSet = _parsePyrightComment(value, textRange, isCommentOnOwnLine, ruleSet, diagnostics);
ruleSet = _parseViperComment(value, textRange, isCommentOnOwnLine, ruleSet, diagnostics);
isModified = true;
}
}
@@ -139,16 +139,16 @@ function _overwriteRules(ruleSet: DiagnosticRuleSet, overrideRuleSet: Diagnostic
}
}
function _parsePyrightComment(
function _parseViperComment(
commentValue: string,
commentRange: TextRange,
isCommentOnOwnLine: () => boolean,
ruleSet: DiagnosticRuleSet,
diagnostics: CommentDiagnostic[]
) {
// 支持 "pyright:" 和 "viper:" 两种注释指令前缀。
// "viper:" 是 Viper 语言的官方指令,"pyright:" 保留向后兼容。
const commentPrefix = 'pyright:';
// 主要支持 "viper:" 注释指令前缀,"pyright:" 保留作为兼容别名。
// "viper:" 是 Viper 语言的官方指令。
const commentPrefix = 'viper:';
const viperCommentPrefix = 'viper:';
let operands: string;
let prefixLength: number;
@@ -170,9 +170,9 @@ function _parsePyrightComment(
if (!isCommentOnOwnLine()) {
const diagAddendum = new DiagnosticAddendum();
diagAddendum.addMessage(LocAddendum.pyrightCommentIgnoreTip());
diagAddendum.addMessage(LocAddendum.viperCommentIgnoreTip());
const diag: CommentDiagnostic = {
message: LocMessage.pyrightCommentNotOnOwnLine() + diagAddendum.getString(),
message: LocMessage.viperCommentNotOnOwnLine() + diagAddendum.getString(),
range: commentRange,
};
@@ -198,7 +198,7 @@ function _parsePyrightComment(
length: operand.length,
});
ruleSet = _parsePyrightOperand(trimmedOperand, operandRange, ruleSet, diagnostics);
ruleSet = _parseViperOperand(trimmedOperand, operandRange, ruleSet, diagnostics);
rangeOffset += operand.length + 1;
}
}
@@ -206,7 +206,7 @@ function _parsePyrightComment(
return ruleSet;
}
function _parsePyrightOperand(
function _parseViperOperand(
operand: string,
operandRange: TextRange,
ruleSet: DiagnosticRuleSet,
@@ -240,7 +240,7 @@ function _parsePyrightOperand(
(ruleSet as any)[trimmedRule] = diagLevelValue;
} else {
const diag: CommentDiagnostic = {
message: LocMessage.pyrightCommentInvalidDiagnosticSeverityValue(),
message: LocMessage.viperCommentInvalidDiagnosticSeverityValue(),
range: trimmedRuleValue ? ruleValueRange : ruleRange,
};
diagnostics.push(diag);
@@ -251,7 +251,7 @@ function _parsePyrightOperand(
(ruleSet as any)[trimmedRule] = boolValue;
} else {
const diag: CommentDiagnostic = {
message: LocMessage.pyrightCommentInvalidDiagnosticBoolValue(),
message: LocMessage.viperCommentInvalidDiagnosticBoolValue(),
range: trimmedRuleValue ? ruleValueRange : ruleRange,
};
diagnostics.push(diag);
@@ -259,14 +259,14 @@ function _parsePyrightOperand(
} else if (trimmedRule) {
const diag: CommentDiagnostic = {
message: trimmedRuleValue
? LocMessage.pyrightCommentUnknownDiagnosticRule().format({ rule: trimmedRule })
: LocMessage.pyrightCommentUnknownDirective().format({ directive: trimmedRule }),
? LocMessage.viperCommentUnknownDiagnosticRule().format({ rule: trimmedRule })
: LocMessage.viperCommentUnknownDirective().format({ directive: trimmedRule }),
range: ruleRange,
};
diagnostics.push(diag);
} else {
const diag: CommentDiagnostic = {
message: LocMessage.pyrightCommentMissingDirective(),
message: LocMessage.viperCommentMissingDirective(),
range: ruleRange,
};
diagnostics.push(diag);
@@ -1316,7 +1316,7 @@ function assignParamSpec(
// only a strictly nested reference (`T := F[T]`) has no finite solution.
function typeVarOccursIn(typeVar: TypeVarType, type: Type): boolean {
// A bare top-level TypeVar reference is not a cycle. Compare by name +
// scope id rather than identity since pyright sometimes clones TypeVars.
// scope id rather than identity since vipeye sometimes clones TypeVars.
if (isTypeVar(type) && type.shared.name === typeVar.shared.name && type.priv.scopeId === typeVar.priv.scopeId) {
return false;
}
@@ -58,7 +58,9 @@ import {
isAnyOrUnknown,
isClass,
isClassInstance,
isCConstType,
isCPtrType,
isCStaticType,
isCVoidType,
isFunctionOrOverloaded,
isInstantiableClass,
@@ -1311,6 +1313,18 @@ function validateArithmeticOperation(
return preserveUnknown(leftSubtypeUnexpanded, rightSubtypeUnexpanded);
}
// Viper 扩展:跳过 Viper 修饰类型(CStatic, CConst 等类型修饰符)。
// 这些修饰类型只是类型修饰符(如 static, const),不参与运算。
// 运算时只处理基础类型(如 CInt, str 等)。
if (isViperDialect) {
if (
isCStaticType(leftSubtypeUnexpanded) || isCStaticType(rightSubtypeUnexpanded) ||
isCConstType(leftSubtypeUnexpanded) || isCConstType(rightSubtypeUnexpanded)
) {
return UnknownType.create(isIncomplete);
}
}
const tupleClassType = evaluator.getTupleClassType();
// Special-case __add__ for tuples when the types for both tuples are known.
@@ -37,7 +37,7 @@ export function getTypeShedFallbackPath(fs: Pick<FileSystem, 'getModulePath' | '
return fs.realCasePath(typeshedPath);
}
// In the debug version of Pyright, the code is one level
// In the debug version of Vipeye, the code is one level
// deeper, so we need to look one level up for the typeshed fallback.
const debugTypeshedPath = moduleDirectory.getDirectory().combinePaths(pathConsts.typeshedFallback);
if (fs.existsSync(debugTypeshedPath)) {
@@ -32,7 +32,6 @@ import {
configFileName,
defaultStubsDirectory,
pyprojectTomlName,
viperConfigFileName,
viperProjectFileExt,
viperProjectFileName,
} from '../common/pathConsts';
@@ -832,7 +831,7 @@ export class AnalyzerService {
// project root directory contains the config file.
configFilePath = findConfigFile(this.fs, projectRoot);
// If pyright is being executed from the command line, the working
// If viper is being executed from the command line, the working
// directory may be deep within a project, and we need to walk up the
// directory hierarchy to find the project root.
if (!configFilePath && !commandLineOptions.fromLanguageServer) {
@@ -871,8 +870,8 @@ export class AnalyzerService {
!configFilePath ? pyprojectFilePath?.getDirectory() : undefined
);
if (configs && configs.length > 0) {
// With a pyrightconfig.json set, we want the typeCheckingMode to always be standard
// as that's what the Pyright CLI will expect. Command line options (if not a language server) and
// With a viperconfig.json set, we want the typeCheckingMode to always be standard
// as that's what the Viper CLI will expect. Command line options (if not a language server) and
// the config file can override this.
configOptions.initializeTypeCheckingMode('standard');
@@ -913,7 +912,7 @@ export class AnalyzerService {
// - *.vpj(Viper Project)命中 → 同样强制 'viper'
// - pyproject.toml 含 [tool.viper] → 同样强制 'viper'
// 后两类信号已由 _getExtendedConfigurations / _parsePyprojectTomlFile 写入 _pyprojectDialect。
if (primaryConfigFileName === viperConfigFileName) {
if (primaryConfigFileName === configFileName) {
configOptions.dialect = 'viper';
} else if (primaryConfigFileName === viperProjectFileName) {
configOptions.dialect = 'viper';
@@ -1287,7 +1286,7 @@ export class AnalyzerService {
// Loads the config JSON object from the specified config file along with any
// chained config files specified in the "extends" property (recursively).
// If pyprojectSearchDir is provided and the primary file is a pyproject.toml with no
// [tool.pyright] section, falls back to searching ancestor dirs from pyprojectSearchDir.
// [tool.viper] section, falls back to searching ancestor dirs from pyprojectSearchDir.
private _getExtendedConfigurations(
primaryConfigFileUri: Uri | undefined,
pyprojectSearchDir?: Uri
@@ -1344,7 +1343,7 @@ export class AnalyzerService {
curConfigFileUri = baseConfigUri;
}
// If a pyproject.toml was found but had no [tool.pyright] section, fall back to
// If a pyproject.toml was found but had no [tool.viper] section, fall back to
// searching ancestor directories as if that pyproject.toml didn't exist.
if (configJsonObjs.length === 0 && pyprojectSearchDir) {
const parentDir = pyprojectSearchDir.getDirectory();
@@ -1366,7 +1365,7 @@ export class AnalyzerService {
}
// 解析 TransPyC project.json(Viper 项目配置)。
// project.json 的 schema 与 viperconfig.json/pyrightconfig.json 不同:
// project.json 的 schema 与 viperconfig.json 不同:
// - source_dir:Viper 源码目录(main.py 所在),作为 import 搜索根
// - includes: 额外的 Viper 模块搜索路径(可相对,如 ../../includes)
// compiler / linker / target / options 等编译器配置 LSP 不需要,忽略。
@@ -1453,16 +1452,12 @@ export class AnalyzerService {
const configObj = parse(fileContents);
if (configObj && 'tool' in configObj) {
const toolSection = configObj.tool as Record<string, object>;
// Viper 优先:[tool.viper] 命中时强制 dialect = 'viper'。
// 否则回退到 [tool.pyright],保持原有 Python 行为(dialect = 'python' 默认)。
// 只支持 [tool.viper]:命中时强制 dialect = 'viper'。
// 完全切换后不再回退 [tool.pyright]。
if (toolSection.viper !== undefined) {
this._pyprojectDialect = 'viper';
return toolSection.viper as object;
}
if (toolSection.pyright !== undefined) {
this._pyprojectDialect = 'python';
return toolSection.pyright as object;
}
}
} catch (e: any) {
this._console.error(`Pyproject file parse attempt ${attemptCount} error: ${JSON.stringify(e)}`);
@@ -1470,7 +1465,7 @@ export class AnalyzerService {
}
this._console.info(
`Pyproject file "${pyprojectPath.toUserVisibleString()}" has no "[tool.pyright]" or "[tool.viper]" section.`
`Pyproject file "${pyprojectPath.toUserVisibleString()}" has no "[tool.viper]" section.`
);
return undefined;
});
@@ -2029,11 +2024,10 @@ export class AnalyzerService {
if (event === 'add' || event === 'change') {
const fileName = getFileName(path);
// L10: 同时监听 viperconfig.json / project.json / *.vpj / pyrightconfig.json,
// L10: 同时监听 viperconfig.json / project.json / *.vpj / pyproject.toml,
// 任一文件新增/变更都触发配置重载,从而在用户切换配置文件后自动应用对应 dialect。
if (
fileName === configFileName ||
fileName === viperConfigFileName ||
fileName === viperProjectFileName ||
fileName === pyprojectTomlName ||
fileName.endsWith(viperProjectFileExt)
@@ -1,5 +1,5 @@
import { ReadOnlyFileSystem } from '../common/fileSystem';
import { configFileName, pyprojectTomlName, viperConfigFileName, viperProjectFileExt, viperProjectFileName } from '../common/pathConsts';
import { configFileName, pyprojectTomlName, viperProjectFileExt, viperProjectFileName } from '../common/pathConsts';
import { Uri } from '../common/uri/uri';
import { forEachAncestorDirectory } from '../common/uri/uriUtils';
@@ -20,9 +20,9 @@ export function findConfigFileHereOrUp(fs: ReadOnlyFileSystem, searchPath: Uri):
}
export function findConfigFile(fs: ReadOnlyFileSystem, searchPath: Uri): Uri | undefined {
// Viper 模式优先:先查找 viperconfig.json,未找到时回退到 pyrightconfig.json。
// 只查找 viperconfig.json(完全切换后不再回退 pyrightconfig.json)。
// 调用方(service.ts)依据返回文件名决定是否将 dialect 设为 'viper'。
const viperFileName = searchPath.resolvePaths(viperConfigFileName);
const viperFileName = searchPath.resolvePaths(configFileName);
if (fs.existsSync(viperFileName)) {
return fs.realCasePath(viperFileName);
}
@@ -36,17 +36,12 @@ export function findConfigFile(fs: ReadOnlyFileSystem, searchPath: Uri): Uri | u
}
// TransPyC project.json:仅当 schema 匹配(含 source_dir / compiler / linker 之一)时才返回,
// 否则跳过到 pyrightconfig.json,避免误判其他工具的 project.json。
// 避免误判其他工具的 project.json。
const projectFileName = searchPath.resolvePaths(viperProjectFileName);
if (fs.existsSync(projectFileName) && isViperProjectConfig(fs, projectFileName)) {
return fs.realCasePath(projectFileName);
}
const pyrightFileName = searchPath.resolvePaths(configFileName);
if (fs.existsSync(pyrightFileName)) {
return fs.realCasePath(pyrightFileName);
}
return undefined;
}
@@ -94,9 +94,9 @@ export class SourceEnumerator {
'* Your workspace contains a symlink to a directory with many files\n' +
'* Your workspace is remote, and file enumeration is slow\n' +
'To reduce this time, open a workspace directory with fewer files ' +
'or add a pyrightconfig.json configuration file with an "exclude" section to exclude ' +
'or add a viperconfig.json configuration file with an "exclude" section to exclude ' +
'subdirectories from your workspace. For more details, refer to ' +
'https://github.com/microsoft/pyright/blob/main/docs/configuration.md.'
'https://github.com/TermiNexus/TransPyC/wiki/viper-configuration.'
);
this._loggedLongOperationError = true;
@@ -127,7 +127,7 @@ class WriteableData {
taskListDiagnostics: Diagnostic[] = [];
typeIgnoreLines = new Map<number, IgnoreComment>();
typeIgnoreAll: IgnoreComment | undefined;
pyrightIgnoreLines = new Map<number, IgnoreComment>();
viperIgnoreLines = new Map<number, IgnoreComment>();
// Accumulated and filtered diagnostics that combines all of the
// above information. This needs to be recomputed any time the
@@ -190,7 +190,7 @@ class WriteableData {
taskListDiagnostics=${this.taskListDiagnostics?.length},
accumulatedDiagnostics=${this.accumulatedDiagnostics?.length},
typeIgnoreLines=${this.typeIgnoreLines?.size},
pyrightIgnoreLines=${this.pyrightIgnoreLines?.size},
viperIgnoreLines=${this.viperIgnoreLines?.size},
checkTime=${this.checkTime},
clientDocumentContents=${this.clientDocumentContents?.length},
parseResults=${this.parserOutput?.parseTree.length},
@@ -755,7 +755,7 @@ export class SourceFile {
this._writableData.parsedFileContents = fileContents;
this._writableData.typeIgnoreLines = parseFileResults.tokenizerOutput.typeIgnoreLines;
this._writableData.typeIgnoreAll = parseFileResults.tokenizerOutput.typeIgnoreAll;
this._writableData.pyrightIgnoreLines = parseFileResults.tokenizerOutput.pyrightIgnoreLines;
this._writableData.viperIgnoreLines = parseFileResults.tokenizerOutput.viperIgnoreLines;
this._writableData.lineCount = parseFileResults.tokenizerOutput.lines.length;
// Cache the tokenizer output only if this file is open.
@@ -841,7 +841,7 @@ export class SourceFile {
lines: this._writableData.tokenizerLines,
typeIgnoreAll: undefined,
typeIgnoreLines: new Map<number, IgnoreComment>(),
pyrightIgnoreLines: new Map<number, IgnoreComment>(),
viperIgnoreLines: new Map<number, IgnoreComment>(),
predominantEndOfLineSequence: '\n',
hasPredominantTabSequence: false,
predominantTabSequence: ' ',
@@ -1080,7 +1080,7 @@ export class SourceFile {
const prefilteredDiagList = diagList;
const typeIgnoreLinesClone = new Map(this._writableData.typeIgnoreLines);
const pyrightIgnoreLinesClone = new Map(this._writableData.pyrightIgnoreLines);
const viperIgnoreLinesClone = new Map(this._writableData.viperIgnoreLines);
// Filter the diagnostics based on "type: ignore" lines.
if (this._diagnosticRuleSet.enableTypeIgnoreComments) {
@@ -1104,8 +1104,8 @@ export class SourceFile {
}
}
// Filter the diagnostics based on "pyright: ignore" lines.
if (this._writableData.pyrightIgnoreLines.size > 0) {
// Filter the diagnostics based on "viper: ignore" lines.
if (this._writableData.viperIgnoreLines.size > 0) {
diagList = diagList.filter((d) => {
if (
d.category !== DiagnosticCategory.UnusedCode &&
@@ -1113,10 +1113,10 @@ export class SourceFile {
d.category !== DiagnosticCategory.Deprecated
) {
for (let line = d.range.start.line; line <= d.range.end.line; line++) {
const pyrightIgnoreComment = this._writableData.pyrightIgnoreLines.get(line);
if (pyrightIgnoreComment) {
if (!pyrightIgnoreComment.rulesList) {
pyrightIgnoreLinesClone.delete(line);
const viperIgnoreComment = this._writableData.viperIgnoreLines.get(line);
if (viperIgnoreComment) {
if (!viperIgnoreComment.rulesList) {
viperIgnoreLinesClone.delete(line);
return false;
}
@@ -1128,17 +1128,17 @@ export class SourceFile {
}
// Did we find this rule in the list?
if (pyrightIgnoreComment.rulesList.find((rule) => rule.text === diagRule)) {
// Update the pyrightIgnoreLinesClone to remove this rule.
const oldClone = pyrightIgnoreLinesClone.get(line);
if (viperIgnoreComment.rulesList.find((rule) => rule.text === diagRule)) {
// Update the viperIgnoreLinesClone to remove this rule.
const oldClone = viperIgnoreLinesClone.get(line);
if (oldClone?.rulesList) {
const filteredRulesList = oldClone.rulesList.filter(
(rule) => rule.text !== diagRule
);
if (filteredRulesList.length === 0) {
pyrightIgnoreLinesClone.delete(line);
viperIgnoreLinesClone.delete(line);
} else {
pyrightIgnoreLinesClone.set(line, {
viperIgnoreLinesClone.set(line, {
range: oldClone.range,
rulesList: filteredRulesList,
});
@@ -1210,7 +1210,7 @@ export class SourceFile {
}
});
pyrightIgnoreLinesClone.forEach((ignoreComment) => {
viperIgnoreLinesClone.forEach((ignoreComment) => {
if (this._writableData.tokenizerLines!) {
if (!ignoreComment.rulesList) {
const rangeStart = ignoreComment.range.start;
@@ -1235,7 +1235,7 @@ export class SourceFile {
if (!isUnreachableCodeRange(range)) {
const diag = new Diagnostic(
diagCategory,
LocMessage.unnecessaryPyrightIgnoreRule().format({
LocMessage.unnecessaryViperIgnoreRule().format({
name: unusedRule.text,
}),
range
@@ -43,6 +43,7 @@ import {
AssignmentNode,
AugmentedAssignmentNode,
AwaitNode,
BinaryOperationNode,
CallNode,
CaseNode,
ClassNode,
@@ -257,6 +258,7 @@ import {
isCConstType,
isCStaticType,
isViperIntegerType,
isViperCIntegerTypeName,
isOverloaded,
isParamSpec,
isPositionOnlySeparator,
@@ -1088,7 +1090,7 @@ export function createTypeEvaluator(
prefetched.awaitableClass = getTypingType(node, 'Awaitable');
prefetched.mappingClass = getTypingType(node, 'Mapping');
// Don't attempt to resolve the string.templatelib if pyright is configured for
// Don't attempt to resolve the string.templatelib if viper is configured for
// Python 3.13 or older. Doing so will either fail to resolve (if running on Python 3.13
// or older) or resolve to the templatelib.py source file (if running on Python 3.14).
if (PythonVersion.isGreaterOrEqualTo(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_14)) {
@@ -4955,11 +4957,28 @@ export function createTypeEvaluator(
}
if (effectiveTypeInfo.isRecursiveDefinition && isNodeReachable(node)) {
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.recursiveDefinition().format({ name }),
node
);
// Viper 扩展:循环引用包含 CPtr 时不报错。
// C 语义中,struct 含指向自身的指针是合法的(如链表节点):
// struct Node { struct Node* next; }
// 对应 Viper: next: 'Node' | t.CPtr
// 指针大小固定,不需要知道结构体的完整定义,打破了无限递归。
// 但无 CPtr 的循环引用(如 next: 'Node')是真正的无限递归,应报错。
const isViperPtrCycle =
IsViperDialect(fileInfo.executionEnvironment.dialect) &&
symbol.getTypedDeclarations().some((decl) => {
if (decl.type !== DeclarationType.Variable || !decl.typeAnnotationNode) {
return false;
}
return typeAnnotationContainsCPtr(decl.typeAnnotationNode);
});
if (!isViperPtrCycle) {
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.recursiveDefinition().format({ name }),
node
);
}
}
const isSpecialBuiltIn =
@@ -8914,6 +8933,172 @@ export function createTypeEvaluator(
return entryTypes;
}
// Viper 扩展:判断调用节点是否为 Viper C 整数类型的构造调用。
// 支持两种形式:
// 1. 直接名称调用:CUInt32T(addr, t.CPtr)
// 2. 成员访问调用:t.CUInt32T(addr, t.CPtr)
// 通过提取调用表达式左侧的名称(CUInt32T),查询 _viperCIntegerTypeNames 白名单判断。
function isViperCIntegerCall(node: CallNode): boolean {
const leftExpr = node.d.leftExpr;
let name: string | undefined;
if (leftExpr.nodeType === ParseNodeType.Name) {
// 形式 1:直接名称调用
name = leftExpr.d.value;
} else if (leftExpr.nodeType === ParseNodeType.MemberAccess) {
// 形式 2:成员访问调用(如 t.CUInt32T)
name = leftExpr.d.member.d.value;
}
return name !== undefined && isViperCIntegerTypeName(name);
}
// Viper 扩展:判断调用节点是否为 __sizeof__ 方法调用。
// 支持两种形式:
// 1. 类调用:Type.__sizeof__()
// 2. 实例调用:instance.__sizeof__()
// Viper 中 __sizeof__ 是类方法(sizeof(Type) -> int),不需要 self 参数。
function isViperSizeOfCall(node: CallNode): boolean {
const leftExpr = node.d.leftExpr;
if (leftExpr.nodeType === ParseNodeType.MemberAccess) {
return leftExpr.d.member.d.value === '__sizeof__';
}
return false;
}
// Viper 扩展:检查类型注解 AST 节点是否包含 CPtr 引用。
// 用于判断循环引用是否被指针打破(如 next: 'Node' | t.CPtr)。
// 递归遍历类型注解表达式,查找名称为 CPtr/CNeedPtr/CAutoPtr/CArrayPtr 的标识符。
function typeAnnotationContainsCPtr(node: ExpressionNode): boolean {
return checkCPtrRecursively(node);
}
function checkCPtrRecursively(node: ParseNode): boolean {
if (!node) {
return false;
}
// 检查名称节点是否为 CPtr 系列
if (node.nodeType === ParseNodeType.Name) {
const name = (node as NameNode).d.value;
return name === 'CPtr' || name === 'CNeedPtr' || name === 'CAutoPtr' || name === 'CArrayPtr';
}
// 检查成员访问节点(如 t.CPtr),检查成员名
if (node.nodeType === ParseNodeType.MemberAccess) {
const memberAccess = node as MemberAccessNode;
const memberName = memberAccess.d.member.d.value;
if (
memberName === 'CPtr' || memberName === 'CNeedPtr' ||
memberName === 'CAutoPtr' || memberName === 'CArrayPtr'
) {
return true;
}
// 继续检查左侧表达式
return checkCPtrRecursively(memberAccess.d.leftExpr);
}
// 检查二进制操作节点(如 'Node' | t.CPtr),递归检查两侧
if (node.nodeType === ParseNodeType.BinaryOperation) {
const binaryOp = node as BinaryOperationNode;
return checkCPtrRecursively(binaryOp.d.leftExpr) || checkCPtrRecursively(binaryOp.d.rightExpr);
}
// 检查索引节点(如 CPtr[Node]),递归检查左侧和索引项
if (node.nodeType === ParseNodeType.Index) {
const indexNode = node as IndexNode;
if (checkCPtrRecursively(indexNode.d.leftExpr)) {
return true;
}
for (const item of indexNode.d.items) {
if (checkCPtrRecursively(item.d.valueExpr)) {
return true;
}
}
return false;
}
// 检查字符串列表节点(字符串注解如 'Node'),检查字符串内容
if (node.nodeType === ParseNodeType.StringList) {
const stringList = node as StringListNode;
for (const stringNode of stringList.d.strings) {
if (stringNode.nodeType === ParseNodeType.String) {
const strValue = (stringNode as any).d?.value ?? '';
// 检查字符串注解中是否包含 CPtr 引用
if (/\b(CPtr|CNeedPtr|CAutoPtr|CArrayPtr)\b/.test(strValue)) {
return true;
}
}
}
return false;
}
// 检查类型注解节点(如 x: Type),递归检查类型表达式
if (node.nodeType === ParseNodeType.TypeAnnotation) {
const typeAnnot = node as TypeAnnotationNode;
return checkCPtrRecursively(typeAnnot.d.typeAnnotation);
}
// 对于其他节点类型,尝试遍历子节点
const d = (node as any).d;
if (d && typeof d === 'object') {
for (const key of Object.keys(d)) {
const value = d[key];
if (value && typeof value === 'object' && value.nodeType !== undefined) {
if (checkCPtrRecursively(value)) {
return true;
}
} else if (Array.isArray(value)) {
for (const item of value) {
if (item && typeof item === 'object' && item.nodeType !== undefined) {
if (checkCPtrRecursively(item)) {
return true;
}
}
}
}
}
}
return false;
}
// Viper 扩展:检测 C 整数类型构造调用的第二参数是否为 t.CPtr。
// 若是,则返回 CPtr 类的 instantiable 形式,用于构造 CPtr[T] 指针类型;
// 否则返回 undefined。
// 示例:t.CUInt32T(addr, t.CPtr) → 返回 CPtr 类,外层构造 CPtr[CUInt32T]。
//
// 判断方式:评估第二参数表达式的类型,若为 instantiable CPtr 类则匹配。
// 这样可以正确处理 t.CPtr、CPtr(直接引用)以及别名导入等各种形式。
function tryGetCPtrTypeFromSecondArg(
node: CallNode
): ClassType | undefined {
if (node.d.args.length < 2) {
return undefined;
}
const secondArgExpr = node.d.args[1].d.valueExpr;
// 若是关键字参数且名字不是 base,则跳过(仅识别位置参数或 base=... 形式)
const argName = node.d.args[1].d.name;
if (argName && argName.d.value !== 'base') {
return undefined;
}
// 评估第二参数表达式的类型
const secondArgTypeResult = getTypeOfExpression(
secondArgExpr,
EvalFlags.CallBaseDefaults
);
const secondArgType = secondArgTypeResult.type;
// 期望第二参数为 CPtr 类的 instantiable 形式(type[CPtr])
if (isInstantiableClass(secondArgType) && isCPtrType(secondArgType)) {
return secondArgType;
}
return undefined;
}
function getTypeOfCall(
node: CallNode,
flags: EvalFlags,
@@ -8993,6 +9178,45 @@ export function createTypeEvaluator(
} else {
addDiagnostic(DiagnosticRule.reportCallIssue, LocMessage.revealLocalsArgs(), node);
}
} else if (
// Viper 扩展:拦截 C 整数类型的构造调用(如 t.CUInt32T(addr, t.CPtr))。
// 这些类型在 vipershed-fallback/stdlib/t.vpi 中定义为 TypeAlias = int,
// 但在 Viper 语义中它们是独立的 C 整数类型,构造调用应支持指针强转语义,
// 而不是走 int.__new__ 的参数类型检查(int.__new__ 期望 str|bytes|bytearray,
// 而 Viper 强转常用指针地址作为参数)。
IsViperDialect(AnalyzerNodeInfo.getFileInfo(node).executionEnvironment.dialect) &&
isInstantiableClass(baseTypeResult.type) &&
ClassType.isBuiltIn(baseTypeResult.type, 'int') &&
isViperCIntegerCall(node)
) {
// 跳过 int.__new__ 的参数类型检查,直接返回该整数类型的实例。
// Viper 的 C 整数类型构造调用本质是 C 语言的强转 (uint32_t)addr,
// 参数类型检查由 Viper 编译器在语义分析阶段处理,LSP 不需要重复检查。
//
// 特殊形式:当第二参数为 t.CPtr 时(如 t.CUInt32T(addr, t.CPtr)),
// 语义是强转为"指向该整数类型的指针"(即 (uint32_t*)addr),
// 此时返回 CPtr[T] 实例类型,以支持指针下标赋值 ptr[i] = value。
const integerInstanceType = ClassType.cloneAsInstance(baseTypeResult.type);
const cptrPointerType = tryGetCPtrTypeFromSecondArg(node);
if (cptrPointerType) {
// 构造 CPtr[IntegerT] 实例类型
const cptrInstance = ClassType.cloneAsInstance(cptrPointerType);
typeResult.type = ClassType.specialize(cptrInstance, [integerInstanceType]);
} else {
typeResult.type = integerInstanceType;
}
} else if (
// Viper 扩展:拦截 __sizeof__ 调用。
// Viper 中 __sizeof__ 语义是 C 语言的 sizeof(Type) -> int,
// 是类方法/静态方法,不需要 self 参数。但 object.__sizeof__ 是实例方法,
// 当通过类调用 Type.__sizeof__() 时会报 "Argument missing for parameter self"。
// 此处跳过参数检查,直接返回 int 类型。
IsViperDialect(AnalyzerNodeInfo.getFileInfo(node).executionEnvironment.dialect) &&
isViperSizeOfCall(node)
) {
// Viper 的 __sizeof__ 是类方法(sizeof(Type)),返回类型大小(字节数)。
// 跳过 object.__sizeof__ 的实例方法参数检查,直接返回 int。
typeResult.type = getBuiltInObject(node, 'int');
} else {
const callResult = validateCallArgs(
node,
@@ -10308,7 +10532,7 @@ export function createTypeEvaluator(
recursionCount++;
// Viper 方言允许联合类型强转,例如 `(memory_block | t.CPtr)(addr)`
// 或 `(t.CInt | t.CPtr)(x)`。Pyright 会把联合类型标记为 specialForm
// 或 `(t.CInt | t.CPtr)(x)`。Vipeye 会把联合类型标记为 specialForm
// 并在上方报 objectNotCallable;Viper 是 AOT 静态语言,这类联合强转是
// 合法语义(C 风格类型转换),因此在 Viper 模式下直接放行并返回 Unknown,
// 避免对联合类型逐子类型校验时产生的误报。
@@ -10613,7 +10837,7 @@ export function createTypeEvaluator(
}
// Ignore instance variables. Also, ignore named tuple members, which are
// modeled in pyright as instance variables, but their runtime implementation
// modeled in vipeye as instance variables, but their runtime implementation
// uses a descriptor object.
if (!symbol.isClassMember() && !symbol.isNamedTupleMemberMember()) {
return undefined;
@@ -27912,7 +28136,7 @@ export function createTypeEvaluator(
// we may be able to narrow the type based on the assignment.
function narrowTypeBasedOnAssignment(declaredType: Type, assignedTypeResult: TypeResult): TypeResult {
// TODO: The rules for narrowing types on assignment are not defined in
// the typing spec. Pyright's current logic is currently not even internally
// the typing spec. Vipeye's current logic is currently not even internally
// consistent and probably not sound from a type theory perspective. It
// should be completely reworked once there has been a public discussion
// about the correct behavior.
@@ -740,7 +740,7 @@ class TypeStubTreeWalker extends ParseTreeWalker {
return (
'"""' +
this._lineEnd +
'This type stub file was generated by pyright.' +
'This type stub file was generated by viper.' +
this._lineEnd +
'"""' +
this._lineEnd +
@@ -3246,6 +3246,43 @@ export function isViperIntegerType(type: Type): boolean {
return ClassType.isBuiltIn(type, 'int');
}
// Viper 扩展:Viper C 整数类型名称白名单。
// 这些类型在 vipershed-fallback/stdlib/t.vpi 中定义为 TypeAlias = int,
// 但在 Viper 语义中它们是独立的 C 整数类型,构造调用应支持指针强转语义,
// 而不是走 int.__new__ 的参数类型检查。
const _viperCIntegerTypeNames = new Set<string>([
// 基本整数类型
'CChar', 'CShort', 'CInt', 'CLong', 'CLongLong',
'CSignedChar', 'CUnsignedChar', 'CUnsignedShort',
'CUnsignedInt', 'CUnsignedLong', 'CUnsignedLongLong',
// 固定宽度整数
'CInt8T', 'CInt16T', 'CInt32T', 'CInt64T',
'CUInt8T', 'CUInt16T', 'CUInt32T', 'CUInt64T',
// 最小/最快宽度整数
'CIntLeast8T', 'CIntLeast16T', 'CIntLeast32T', 'CIntLeast64T',
'CUIntLeast8T', 'CUIntLeast16T', 'CUIntLeast32T', 'CUIntLeast64T',
'CIntFast8T', 'CIntFast16T', 'CIntFast32T', 'CIntFast64T',
'CUIntFast8T', 'CUIntFast16T', 'CUIntFast32T', 'CUIntFast64T',
// 最大宽度整数
'CIntMaxT', 'CUIntMaxT',
// 平台相关整数
'CSizeT', 'CIntPtrT', 'CUIntPtrT', 'CPtrDiffT',
// 布尔
'CBool',
// 宽字符
'CWCharT', 'CChar8T', 'CChar16T', 'CChar32T',
// LLVM 简写
'i1', 'i8', 'i16', 'i32', 'i64',
'u1', 'u8', 'u16', 'u32', 'u64',
]);
// Viper 扩展:检测名称是否为 Viper C 整数类型名。
// 用于在 getTypeOfCall 中识别 C 整数类型的构造调用(如 t.CUInt32T(addr, t.CPtr)),
// 并跳过 int.__new__ 的参数类型检查,实现 Viper 的指针强转语义。
export function isViperCIntegerTypeName(name: string): boolean {
return _viperCIntegerTypeNames.has(name);
}
export function isAny(type: Type): type is AnyType {
return type.category === TypeCategory.Any;
}
@@ -274,7 +274,7 @@ class DefaultTypeshedInfoProvider implements TypeshedInfoProvider {
}
// Viper 模式仍使用 typeshed-fallback 作为 typeshed root,
// 确保 builtins/typing 等基础模块可被 Pyright 隐式加载。
// 确保 builtins/typing 等基础模块可被 Vipeye 隐式加载。
// Viper 特有模块(t/c/stdio 等)通过 importResolver.getImportRoots()
// 额外添加 vipershed-fallback/stdlib 作为优先搜索路径。
const fallback = PythonPathUtils.getTypeShedFallbackPath(this._fileSystem) ?? Uri.empty();
@@ -3,7 +3,7 @@
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*
* helpers shared between multiple packages such as vipeye-internal and pyright
* helpers shared between multiple packages such as vipeye-internal and vipeye
*/
import { ensureTomlModuleLoaded } from './tomlUtils';
@@ -34,7 +34,7 @@ export type DiagnosticSeverityOverridesMap = { [ruleName: string]: DiagnosticSev
export type DiagnosticBooleanOverridesMap = { [ruleName: string]: boolean };
// Options that can be specified in a JSON config file. This list should match what is
// defined in the pyrightconfig.schema.json file.
// defined in the vipeyeconfig.schema.json file.
export class CommandLineConfigOptions {
// A list of file specs to include in the analysis. Can contain
// directories, in which case all "*.py" files within those directories
@@ -156,7 +156,7 @@ export class CommandLineLanguageServerOptions {
venvPath?: string | undefined;
}
// Some options can be specified from a source other than the pyright config file.
// Some options can be specified from a source other than the viper config file.
// This can be from command-line parameters or some other settings mechanism, like
// that provided through a language client like the VS Code editor. These options
// are later combined with those from the config file to produce the final configuration.
@@ -392,7 +392,7 @@ export interface DiagnosticRuleSet {
// Report cases where a simple expression result is not used in any way.
reportUnusedExpression: DiagnosticLevel;
// Report cases where the removal of a "# type: ignore" or "# pyright: ignore"
// Report cases where the removal of a "# type: ignore" or "# viper: ignore"
// comment would have no effect.
reportUnnecessaryTypeIgnoreComment: DiagnosticLevel;
@@ -429,7 +429,7 @@ export function getBooleanDiagnosticRules(includeNonOverridable = false) {
if (includeNonOverridable) {
// Do not include these because we don't
// want to override it in strict mode or support
// it within pyright comments.
// it within viper comments.
boolRules.push(DiagnosticRule.enableTypeIgnoreComments);
boolRules.push(DiagnosticRule.enableReachabilityAnalysis);
}
@@ -1095,7 +1095,7 @@ export class ConfigOptions {
// Minimum threshold for type eval logging
typeEvaluationTimeThreshold = 50;
// Was this config initialized from JSON (pyrightconfig/pyproject)?
// Was this config initialized from JSON (viperconfig/pyproject)?
initializedFromJson = false;
// Filter out any hint diagnostics with tags?
@@ -1155,7 +1155,7 @@ export class ConfigOptions {
// Controls how hover and completion function signatures are displayed.
functionSignatureDisplay: SignatureDisplayType;
// Determines if has a config file (pyrightconfig.json or pyproject.toml) or not.
// Determines if has a config file (viperconfig.json or pyproject.toml) or not.
configFileSource?: Uri | undefined;
// Determines the effective default type checking mode.
@@ -3,7 +3,7 @@
* 语言方言开关:区分 Python 与 Viper 语义。
*
* Viper 是基于 CPython 语法但语义不同的 AOT 编译型语言。
* 在 TPV --lsp 实现前,Pyright(Vipeye)作为姑息 LSP 充当分析器。
* 在 TPV --lsp 实现前,Vipeye 作为姑息 LSP 充当分析器。
* 通过 dialect 字段在 Python 语义与 Viper 语义之间切换。
*/
@@ -50,7 +50,7 @@ export namespace DocStringService {
}
}
export class PyrightDocStringService implements DocStringService {
export class ViperDocStringService implements DocStringService {
convertDocStringToPlainText(docString: string): string {
return convertDocStringToPlainText(docString);
}
@@ -23,10 +23,9 @@ export const defaultStubsDirectory = 'typings';
export const requirementsFileName = 'requirements.txt';
export const pyprojectTomlName = 'pyproject.toml';
export const dotPythonVersionName = '.python-version';
export const configFileName = 'pyrightconfig.json';
// Viper 模式下的配置文件名(替代 pyrightconfig.json)。
export const viperConfigFileName = 'viperconfig.json';
// 配置文件名。完全切换后只认 viperconfig.json(原 pyrightconfig.json 已废弃)。
// viperConfigFileName 已合并到 configFileName,外部引用请统一使用 configFileName。
export const configFileName = 'viperconfig.json';
// Viper 项目配置文件名(TransPyC 编译器使用)。
// schema 与 viperconfig.json 不同:含 source_dir / includes / compiler / linker 等字段。
@@ -564,7 +564,7 @@ export class RealTempFile implements TempFile, CaseSensitivityDetector {
}
const osTempRoot = os.tmpdir();
const configuredTmpRoot = process.env.PYRIGHT_TMPDIR?.trim();
const configuredTmpRoot = process.env.VIPER_TMPDIR?.trim();
type TmpDirOutcome = {
tmpdir?: tmp.DirResult;
@@ -586,7 +586,7 @@ export class RealTempFile implements TempFile, CaseSensitivityDetector {
return { error: e };
}
return createTmpDir({ prefix: 'pyright', tmpdir: root });
return createTmpDir({ prefix: 'viper', tmpdir: root });
};
// Highest priority: explicit override.
@@ -599,7 +599,7 @@ export class RealTempFile implements TempFile, CaseSensitivityDetector {
}
// Default behavior: let tmp/os decide.
const defaultOutcome = createTmpDir({ prefix: 'pyright' });
const defaultOutcome = createTmpDir({ prefix: 'viper' });
if (defaultOutcome.tmpdir) {
this._tmpdir = defaultOutcome.tmpdir;
return this._tmpdir;
@@ -610,8 +610,8 @@ export class RealTempFile implements TempFile, CaseSensitivityDetector {
const details = defaultError?.message ?? String(defaultOutcome.error);
throw new Error(
`Failed to create a temporary directory for Pyright. The OS temp directory root is "${osTempRoot}". ` +
`If that path doesn't exist or isn't writable, set PYRIGHT_TMPDIR or TMPDIR/TMP/TEMP for the VS Code server/extension host process ` +
`Failed to create a temporary directory for Viper. The OS temp directory root is "${osTempRoot}". ` +
`If that path doesn't exist or isn't writable, set VIPER_TMPDIR or TMPDIR/TMP/TEMP for the VS Code server/extension host process ` +
`or ensure the env vars are inherited by the remote/server process. ` +
`Original error: ${details}`
);
@@ -12,7 +12,7 @@ import { PartialStubService, SupportPartialStubs } from '../partialStubService';
import { CancellationProvider, DefaultCancellationProvider } from './cancellationUtils';
import { CaseSensitivityDetector } from './caseSensitivityDetector';
import { ConsoleInterface, NullConsole } from './console';
import { DocStringService, PyrightDocStringService } from './docStringService';
import { DocStringService, ViperDocStringService } from './docStringService';
import { FileSystem, TempFile } from './fileSystem';
import { CommandService, WindowService } from './languageServerInterface';
import { LogTracker } from './logTracker';
@@ -110,7 +110,7 @@ ServiceProvider.prototype.sourceFileFactory = function () {
ServiceProvider.prototype.docStringService = function () {
const result = this.tryGet(ServiceKeys.docStringService);
return result || new PyrightDocStringService();
return result || new ViperDocStringService();
};
ServiceProvider.prototype.cacheManager = function () {
@@ -3,7 +3,7 @@
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*
* Convert pyright's FileEditActions to LanguageServer's WorkspaceEdits.
* Convert vipeye's FileEditActions to LanguageServer's WorkspaceEdits.
*/
import {
@@ -407,7 +407,7 @@ export abstract class LanguageServerBase implements LanguageServerInterface, Dis
this.workspaceFactory.items().forEach((workspace) => {
// Updating settings can change workspace's file ownership. Make workspace uninitialized so that
// features can wait until workspace gets new settings.
// the file's ownership can also changed by `pyrightconfig.json` changes, but those are synchronous
// the file's ownership can also changed by `viperconfig.json` changes, but those are synchronous
// operation, so it won't affect this.
workspace.isInitialized = workspace.isInitialized.reset();
tasks.push(this.updateSettingsForWorkspace(workspace, workspace.isInitialized));
@@ -1578,7 +1578,7 @@ export abstract class LanguageServerBase implements LanguageServerInterface, Dis
const rule = diag.getRule();
if (rule) {
// Configuration.md is configured to have a link for every rule name.
return `https://github.com/microsoft/pyright/blob/main/docs/configuration.md#${rule}`;
return `https://github.com/TermiNexus/TransPyC/wiki/viper-configuration#${rule}`;
}
return undefined;
}
@@ -132,7 +132,7 @@ export function getEffectiveCommandLineOptions(
}
if (serverSettings.typeshedPath) {
// Pyright supports only one typeshed path currently, whereas the
// Vipeye supports only one typeshed path currently, whereas the
// official VS Code Python extension supports multiple typeshed paths.
// We'll use the first one specified and ignore the rest.
commandLineOptions.configSettings.typeshedPath = serverSettings.typeshedPath.getFilePath();
@@ -17,7 +17,7 @@ export class PullDiagnosticsDynamicFeature extends DynamicFeature {
private _workspaceSupport = false;
private _registered = false;
constructor(private readonly _connection: Connection, private readonly _id: string = 'pyright') {
constructor(private readonly _connection: Connection, private readonly _id: string = 'viper') {
super('pull diagnostics');
}
@@ -16,6 +16,7 @@
import { Declaration, DeclarationType, VariableDeclaration } from '../analyzer/declaration';
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
import { isWithinTypeAnnotation } from '../analyzer/parseTreeUtils';
import { TypeCategory } from '../analyzer/types';
import { TypeEvaluator } from '../analyzer/typeEvaluatorTypes';
import { LogTracker } from '../common/logTracker';
@@ -436,8 +437,13 @@ class SemanticTokenWalker extends ParseTreeWalker {
return false;
}
/** 访问 StringNode:字符串字面量 → string */
/** 访问 StringNode:字符串字面量 → string。
* Viper 扩展:在类型注解上下文中的字符串(前向引用)不生成 string token,
* 让 TextMate 语法规则处理高亮(显示为类型颜色而非字符串颜色)。 */
override visitString(node: StringNode): boolean {
if (isWithinTypeAnnotation(node, /* requireQuotedAnnotation */ false)) {
return true;
}
this._pushLiteralToken(node.start, node.length, SemanticTokenTypes.string);
return true;
}
@@ -867,16 +867,16 @@ export namespace Localizer {
new ParameterizedString<{ variable: string; class: string }>(
getRawString('Diagnostic.protocolVarianceInvariant')
);
export const pyrightCommentInvalidDiagnosticBoolValue = () =>
getRawString('Diagnostic.pyrightCommentInvalidDiagnosticBoolValue');
export const pyrightCommentInvalidDiagnosticSeverityValue = () =>
getRawString('Diagnostic.pyrightCommentInvalidDiagnosticSeverityValue');
export const pyrightCommentMissingDirective = () => getRawString('Diagnostic.pyrightCommentMissingDirective');
export const pyrightCommentNotOnOwnLine = () => getRawString('Diagnostic.pyrightCommentNotOnOwnLine');
export const pyrightCommentUnknownDirective = () =>
new ParameterizedString<{ directive: string }>(getRawString('Diagnostic.pyrightCommentUnknownDirective'));
export const pyrightCommentUnknownDiagnosticRule = () =>
new ParameterizedString<{ rule: string }>(getRawString('Diagnostic.pyrightCommentUnknownDiagnosticRule'));
export const viperCommentInvalidDiagnosticBoolValue = () =>
getRawString('Diagnostic.viperCommentInvalidDiagnosticBoolValue');
export const viperCommentInvalidDiagnosticSeverityValue = () =>
getRawString('Diagnostic.viperCommentInvalidDiagnosticSeverityValue');
export const viperCommentMissingDirective = () => getRawString('Diagnostic.viperCommentMissingDirective');
export const viperCommentNotOnOwnLine = () => getRawString('Diagnostic.viperCommentNotOnOwnLine');
export const viperCommentUnknownDirective = () =>
new ParameterizedString<{ directive: string }>(getRawString('Diagnostic.viperCommentUnknownDirective'));
export const viperCommentUnknownDiagnosticRule = () =>
new ParameterizedString<{ rule: string }>(getRawString('Diagnostic.viperCommentUnknownDiagnosticRule'));
export const readOnlyArgCount = () => getRawString('Diagnostic.readOnlyArgCount');
export const readOnlyNotInTypedDict = () => getRawString('Diagnostic.readOnlyNotInTypedDict');
export const recursiveDefinition = () =>
@@ -1190,9 +1190,9 @@ export namespace Localizer {
new ParameterizedString<{ testType: string; classType: string }>(
getRawString('Diagnostic.unnecessaryIsSubclassNever')
);
export const unnecessaryPyrightIgnore = () => getRawString('Diagnostic.unnecessaryPyrightIgnore');
export const unnecessaryPyrightIgnoreRule = () =>
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.unnecessaryPyrightIgnoreRule'));
export const unnecessaryViperIgnore = () => getRawString('Diagnostic.unnecessaryViperIgnore');
export const unnecessaryViperIgnoreRule = () =>
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.unnecessaryViperIgnoreRule'));
export const unnecessaryTypeIgnore = () => getRawString('Diagnostic.unnecessaryTypeIgnore');
export const unpackArgCount = () => getRawString('Diagnostic.unpackArgCount');
export const unpackedArgInTypeArgument = () => getRawString('Diagnostic.unpackedArgInTypeArgument');
@@ -1503,7 +1503,7 @@ export namespace Localizer {
);
export const protocolUnsafeOverlap = () =>
new ParameterizedString<{ name: string }>(getRawString('DiagnosticAddendum.protocolUnsafeOverlap'));
export const pyrightCommentIgnoreTip = () => getRawString('DiagnosticAddendum.pyrightCommentIgnoreTip');
export const viperCommentIgnoreTip = () => getRawString('DiagnosticAddendum.viperCommentIgnoreTip');
export const readOnlyAttribute = () =>
new ParameterizedString<{ name: string }>(getRawString('DiagnosticAddendum.readOnlyAttribute'));
export const seeDeclaration = () => getRawString('DiagnosticAddendum.seeDeclaration');
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "Proměnná typu {variable} použitá v obecné třídě Protocol {class} by měla být kontravariantní.",
"protocolVarianceCovariant": "Proměnná typu {variable} použitá v obecné třídě Protocol {class} by měla být kovariantní.",
"protocolVarianceInvariant": "Proměnná typu {variable} použitá v obecné třídě Protocol {class} by měla být invariantní.",
"pyrightCommentInvalidDiagnosticBoolValue": "Za direktivou komentářů Pyright musí následovat znak =a hodnota true nebo false",
"pyrightCommentInvalidDiagnosticSeverityValue": "Za direktivou komentářů Pyright musí následovat = a hodnota true, false, error, warning, information nebo none",
"pyrightCommentMissingDirective": "Za komentářem Pyright musí následovat direktiva (basic nebo strict) nebo diagnostické pravidlo.",
"pyrightCommentNotOnOwnLine": "Komentáře Pyright používané k řízení nastavení na úrovni souborů se musí zobrazovat na vlastním řádku",
"pyrightCommentUnknownDiagnosticRule": "{rule} je neznámé diagnostické pravidlo pro komentář pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "{value} je neplatná hodnota pro komentář pyright; očekávalo se true, false, error, warning, information nebo none",
"pyrightCommentUnknownDirective": "Direktiva {directive} je neznámá direktiva pro komentář pyright; očekávalo se strict, standard nebo basic",
"viperCommentInvalidDiagnosticBoolValue": "Za direktivou komentářů Viper musí následovat znak =a hodnota true nebo false",
"viperCommentInvalidDiagnosticSeverityValue": "Za direktivou komentářů Viper musí následovat = a hodnota true, false, error, warning, information nebo none",
"viperCommentMissingDirective": "Za komentářem Viper musí následovat direktiva (basic nebo strict) nebo diagnostické pravidlo.",
"viperCommentNotOnOwnLine": "Komentáře Viper používané k řízení nastavení na úrovni souborů se musí zobrazovat na vlastním řádku",
"viperCommentUnknownDiagnosticRule": "{rule} je neznámé diagnostické pravidlo pro komentář viper",
"viperCommentUnknownDiagnosticSeverityValue": "{value} je neplatná hodnota pro komentář viper; očekávalo se true, false, error, warning, information nebo none",
"viperCommentUnknownDirective": "Direktiva {directive} je neznámá direktiva pro komentář viper; očekávalo se strict, standard nebo basic",
"readOnlyArgCount": "Za „ReadOnly“ se očekával jeden argument typu",
"readOnlyNotInTypedDict": "ReadOnly není v tomto kontextu povolené",
"recursiveDefinition": "Typ „{name}“ nelze určit, protože odkazuje sám na sebe",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Zbytečné volání isinstance; {testType} není nikdy instancí třídy {classType}",
"unnecessaryIsSubclassAlways": "Nepotřebné volání issubclass; „{testType}“ je vždy podtřídou třídy „{classType}“",
"unnecessaryIsSubclassNever": "Zbytečné volání issubclass; {testType} není nikdy podtřídou třídy {classType}",
"unnecessaryPyrightIgnore": "Nepotřebný komentář „# pyright: ignore“",
"unnecessaryPyrightIgnoreRule": "Nepotřebné pravidlo # pyright: ignore: {name}",
"unnecessaryViperIgnore": "Nepotřebný komentář „# viper: ignore“",
"unnecessaryViperIgnoreRule": "Nepotřebné pravidlo # viper: ignore: {name}",
"unnecessaryTypeIgnore": "Nepotřebný komentář „# type: ignore“",
"unpackArgCount": "Po rozbalení „Unpack“ se očekával jeden argument typu",
"unpackExpectedTypeVarTuple": "Jako argument typu pro Unpack byl očekáván typ TypeVarTuple nebo tuple.",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Třída Protocol musí být @runtime_checkable, aby se použila při kontrolách instancí a tříd.",
"protocolSourceIsNotConcrete": "„{sourceType}“ není konkrétní typ třídy a nedá se přiřadit k typu „{destType}“",
"protocolUnsafeOverlap": "Atributy „{name}“ mají stejné názvy jako protokol.",
"pyrightCommentIgnoreTip": "Pokud chcete potlačit diagnostiku pro jeden řádek, použijte # pyright: ignore[<diagnostic rules>]",
"viperCommentIgnoreTip": "Pokud chcete potlačit diagnostiku pro jeden řádek, použijte # viper: ignore[<diagnostic rules>]",
"readOnlyAttribute": "Atribut {name} je jen pro čtení",
"seeClassDeclaration": "Viz deklarace třídy",
"seeDeclaration": "Viz deklarace",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "Die Typvariable \"{variable}\", die im generischen Protocol \"{class}\" verwendet wird, muss \"contravariant\" sein.",
"protocolVarianceCovariant": "Die Typvariable \"{variable}\", die im generischen Protocol \"{class}\" verwendet wird, muss \"covariant\" sein.",
"protocolVarianceInvariant": "Die Typvariable \"{variable}\", die im generischen Protocol \"{class}\" verwendet wird, muss \"invariant\" sein.",
"pyrightCommentInvalidDiagnosticBoolValue": "Auf die Pyright-Kommentardirektive muss \"=\" und der Wert \"true\" oder \"false\" folgen.",
"pyrightCommentInvalidDiagnosticSeverityValue": "Auf die Pyright-Kommentardirektive muss \"=\" und der Wert \"true\", \"false\", \"error\", \"warning\", \"information\" oder \"none\" folgen.",
"pyrightCommentMissingDirective": "Auf einen Pyright-Kommentar muss eine Direktive (basic oder strict) oder eine Diagnoseregel folgen.",
"pyrightCommentNotOnOwnLine": "Pyright-Kommentare, die zum Steuern von Einstellungen auf Dateiebene verwendet werden, müssen in ihrer eigenen Zeile angezeigt werden.",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\" ist eine unbekannte Diagnoseregel für pyright-Kommentar.",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" ist ein ungültiger Wert für den pyright-Kommentar; \"true\", \"false\", \"error\", \"warning\", \"information\" oder \"none\" erwartet.",
"pyrightCommentUnknownDirective": "„{directive}“ ist eine unbekannte Direktive für pyright-Kommentar; „strict“, „standard“ oder „basic“ erwartet",
"viperCommentInvalidDiagnosticBoolValue": "Auf die Viper-Kommentardirektive muss \"=\" und der Wert \"true\" oder \"false\" folgen.",
"viperCommentInvalidDiagnosticSeverityValue": "Auf die Viper-Kommentardirektive muss \"=\" und der Wert \"true\", \"false\", \"error\", \"warning\", \"information\" oder \"none\" folgen.",
"viperCommentMissingDirective": "Auf einen Viper-Kommentar muss eine Direktive (basic oder strict) oder eine Diagnoseregel folgen.",
"viperCommentNotOnOwnLine": "Viper-Kommentare, die zum Steuern von Einstellungen auf Dateiebene verwendet werden, müssen in ihrer eigenen Zeile angezeigt werden.",
"viperCommentUnknownDiagnosticRule": "\"{rule}\" ist eine unbekannte Diagnoseregel für viper-Kommentar.",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" ist ein ungültiger Wert für den viper-Kommentar; \"true\", \"false\", \"error\", \"warning\", \"information\" oder \"none\" erwartet.",
"viperCommentUnknownDirective": "„{directive}“ ist eine unbekannte Direktive für viper-Kommentar; „strict“, „standard“ oder „basic“ erwartet",
"readOnlyArgCount": "Nach \"ReadOnly\" wurde ein einzelnes Typargument erwartet.",
"readOnlyNotInTypedDict": "\"ReadOnly\" ist in diesem Kontext nicht zulässig.",
"recursiveDefinition": "Der Typ von \"{name}\" konnte nicht bestimmt werden, da er sich auf selbst bezieht.",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Nicht erforderlicher isinstance-Aufruf; \"{testType}\" ist nie eine Instanz von \"{classType}\"",
"unnecessaryIsSubclassAlways": "Nicht erforderlicher issubclass-Aufruf; \"{testType}\" ist immer eine Unterklasse von \"{classType}\"",
"unnecessaryIsSubclassNever": "Nicht erforderlicher issubclass-Aufruf; \"{testType}\" ist nie eine Unterklasse von \"{classType}\"",
"unnecessaryPyrightIgnore": "Unnötiger \"# pyright: ignore\"-Kommentar",
"unnecessaryPyrightIgnoreRule": "Unnötiger \"# pyright: ignore\"-Regel: \"{name}\"",
"unnecessaryViperIgnore": "Unnötiger \"# viper: ignore\"-Kommentar",
"unnecessaryViperIgnoreRule": "Unnötiger \"# viper: ignore\"-Regel: \"{name}\"",
"unnecessaryTypeIgnore": "Nicht erforderlicher \"# type: ignore\"-Kommentar",
"unpackArgCount": "Nach \"Unpack\" wurde ein einzelnes Typargument erwartet.",
"unpackExpectedTypeVarTuple": "„TypeVarTuple“ oder „tuple“ als Typargument für „Unpack“ erwartet",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Die Protocol Klasse muss @runtime_checkable sein, damit sie mit Instanz- und Klassenprüfungen verwendet werden kann.",
"protocolSourceIsNotConcrete": "\"{sourceType}\" ist kein konkreter Klassentyp und kann dem Typ \"{destType}\" nicht zugewiesen werden.",
"protocolUnsafeOverlap": "Attribute von „{name}“ weisen die gleichen Namen wie das Protokoll auf.",
"pyrightCommentIgnoreTip": "Verwenden Sie \"# pyright: ignore[<diagnostic rules>]\", um die Diagnose für eine einzelne Zeile zu unterdrücken.",
"viperCommentIgnoreTip": "Verwenden Sie \"# viper: ignore[<diagnostic rules>]\", um die Diagnose für eine einzelne Zeile zu unterdrücken.",
"readOnlyAttribute": "Das Attribut \"{name}\" ist schreibgeschützt.",
"seeClassDeclaration": "Siehe Klassendeklaration",
"seeDeclaration": "Siehe Deklaration",
@@ -108,11 +108,11 @@
"binaryOperationNotAllowed": "Binary operator not allowed in type expression",
"bindParamMissing": {
"message": "Could not bind method \"{methodName}\" because it is missing a \"self\" or \"cls\" parameter",
"comment": "Binding is the process through which Pyright determines what object a name refers to"
"comment": "Binding is the process through which Viper determines what object a name refers to"
},
"bindTypeMismatch": {
"message": "Could not bind method \"{methodName}\" because \"{type}\" is not assignable to parameter \"{paramName}\"",
"comment": "Binding is the process through which Pyright determines what object a name refers to"
"comment": "Binding is the process through which Viper determines what object a name refers to"
},
"breakInExceptionGroup": {
"message": "\"break\" is not allowed in an \"except*\" block",
@@ -677,7 +677,7 @@
},
"internalBindError": {
"message": "An internal error occurred while binding file \"{file}\": {message}",
"comment": "Binding is the process through which Pyright determines what object a name refers to"
"comment": "Binding is the process through which Viper determines what object a name refers to"
},
"internalParseError": "An internal error occurred while parsing file \"{file}\": {message}",
"internalTypeCheckingError": "An internal error occurred while type checking file \"{file}\": {message}",
@@ -866,7 +866,7 @@
},
"nonLocalNoBinding": {
"message": "No binding for nonlocal \"{name}\" found",
"comment": ["{Locked='nonlocal'}", "'No binding found' means that Pyright couldn't resolve the variable name to an object"]
"comment": ["{Locked='nonlocal'}", "'No binding found' means that Viper couldn't resolve the variable name to an object"]
},
"nonLocalReassignment": {
"message": "\"{name}\" is assigned before nonlocal declaration",
@@ -1095,33 +1095,33 @@
"message": "Type variable \"{variable}\" used in generic Protocol \"{class}\" should be invariant",
"comment": ["{Locked='Protocol'}", "A generic type is a parameterized type, for example a container where the generic type parameter specifies the type of elements in the container"]
},
"pyrightCommentInvalidDiagnosticBoolValue": {
"message": "Pyright comment directive must be followed by \"=\" and a value of true or false",
"comment": "{Locked='Pyright','true','false'}"
"viperCommentInvalidDiagnosticBoolValue": {
"message": "Viper comment directive must be followed by \"=\" and a value of true or false",
"comment": "{Locked='Viper','true','false'}"
},
"pyrightCommentInvalidDiagnosticSeverityValue": {
"message": "Pyright comment directive must be followed by \"=\" and a value of true, false, error, warning, information, or none",
"comment": "{Locked='Pyright','true','false','error','warning','information','none'}"
"viperCommentInvalidDiagnosticSeverityValue": {
"message": "Viper comment directive must be followed by \"=\" and a value of true, false, error, warning, information, or none",
"comment": "{Locked='Viper','true','false','error','warning','information','none'}"
},
"pyrightCommentMissingDirective": {
"message": "Pyright comment must be followed by a directive (basic or strict) or a diagnostic rule",
"comment": "{Locked='Pyright','basic','strict'}"
"viperCommentMissingDirective": {
"message": "Viper comment must be followed by a directive (basic or strict) or a diagnostic rule",
"comment": "{Locked='Viper','basic','strict'}"
},
"pyrightCommentNotOnOwnLine": {
"message": "Pyright comments used to control file-level settings must appear on their own line",
"comment": "{Locked='Pyright'}"
"viperCommentNotOnOwnLine": {
"message": "Viper comments used to control file-level settings must appear on their own line",
"comment": "{Locked='Viper'}"
},
"pyrightCommentUnknownDiagnosticRule": {
"message": "\"{rule}\" is an unknown diagnostic rule for pyright comment",
"comment": "{Locked='pyright'}"
"viperCommentUnknownDiagnosticRule": {
"message": "\"{rule}\" is an unknown diagnostic rule for viper comment",
"comment": "{Locked='viper'}"
},
"pyrightCommentUnknownDiagnosticSeverityValue": {
"message": "\"{value}\" is invalid value for pyright comment; expected true, false, error, warning, information, or none",
"comment": "{Locked='pyright','true','false','error','warning','information','none'}"
"viperCommentUnknownDiagnosticSeverityValue": {
"message": "\"{value}\" is invalid value for viper comment; expected true, false, error, warning, information, or none",
"comment": "{Locked='viper','true','false','error','warning','information','none'}"
},
"pyrightCommentUnknownDirective": {
"message": "\"{directive}\" is an unknown directive for pyright comment; expected \"strict\", \"standard\", or \"basic\"",
"comment": "{Locked='pyright','strict','standard','basic'}"
"viperCommentUnknownDirective": {
"message": "\"{directive}\" is an unknown directive for viper comment; expected \"strict\", \"standard\", or \"basic\"",
"comment": "{Locked='viper','strict','standard','basic'}"
},
"readOnlyArgCount": {
"message": "Expected a single type argument after \"ReadOnly\"",
@@ -1663,13 +1663,13 @@
"message": "Unnecessary issubclass call; \"{testType}\" is never a subclass of \"{classType}\"",
"comment": "{Locked='issubclass'}"
},
"unnecessaryPyrightIgnore": {
"message": "Unnecessary \"# pyright: ignore\" comment",
"comment": "{Locked='# pyright: ignore'}"
"unnecessaryViperIgnore": {
"message": "Unnecessary \"# viper: ignore\" comment",
"comment": "{Locked='# viper: ignore'}"
},
"unnecessaryPyrightIgnoreRule": {
"message": "Unnecessary \"# pyright: ignore\" rule: \"{name}\"",
"comment": "{Locked='# pyright: ignore'}"
"unnecessaryViperIgnoreRule": {
"message": "Unnecessary \"# viper: ignore\" rule: \"{name}\"",
"comment": "{Locked='# viper: ignore'}"
},
"unnecessaryTypeIgnore": {
"message": "Unnecessary \"# type: ignore\" comment",
@@ -1835,7 +1835,7 @@
"dataProtocolUnsupported": "\"{name}\" is a data protocol",
"descriptorAccessBindingFailed": {
"message": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"comment": "Binding is the process through which Pyright determines what object a name refers to"
"comment": "Binding is the process through which Viper determines what object a name refers to"
},
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": {
@@ -2040,9 +2040,9 @@
},
"protocolSourceIsNotConcrete": "\"{sourceType}\" is not a concrete class type and cannot be assigned to type \"{destType}\"",
"protocolUnsafeOverlap": "Attributes of \"{name}\" have the same names as the protocol",
"pyrightCommentIgnoreTip": {
"message": "Use \"# pyright: ignore[<diagnostic rules>]\" to suppress diagnostics for a single line",
"comment": "{Locked='# pyright: ignore[<diagnostic rules>]'}"
"viperCommentIgnoreTip": {
"message": "Use \"# viper: ignore[<diagnostic rules>]\" to suppress diagnostics for a single line",
"comment": "{Locked='# viper: ignore[<diagnostic rules>]'}"
},
"readOnlyAttribute": "Attribute \"{name}\" is read-only",
"seeClassDeclaration": "See class declaration",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "La variable de tipo \"{variable}\" usada en Protocol genérico \"{class}\" debe ser contravariante",
"protocolVarianceCovariant": "La variable de tipo \"{variable}\" usada en Protocol genérico \"{class}\" debe ser covariante",
"protocolVarianceInvariant": "La variable de tipo \"{variable}\" usada en Protocol genérico \"{class}\" debe ser invariable",
"pyrightCommentInvalidDiagnosticBoolValue": "La directiva de comentario Pyright debe ir seguida de \"=\" y un valor de true o false",
"pyrightCommentInvalidDiagnosticSeverityValue": "La directiva de comentario Pyright debe ir seguida de \"=\" y un valor de true, false, error, warning, information o none.",
"pyrightCommentMissingDirective": "El comentario de Pyright debe ir seguido de una directiva (basic o estricta) o de una regla de diagnóstico",
"pyrightCommentNotOnOwnLine": "Los comentarios de Pyright utilizados para controlar los ajustes a nivel de archivo deben aparecer en su propia línea",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\" es una regla de diagnóstico desconocida para el comentario pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" es un valor no válido para el comentario pyright; se espera true, false, error, warning, information o none.",
"pyrightCommentUnknownDirective": "\"{directive}\" es una directiva desconocida para el comentario pyright; se esperaba \"strict\", \"standard\" o \"basic\"",
"viperCommentInvalidDiagnosticBoolValue": "La directiva de comentario Viper debe ir seguida de \"=\" y un valor de true o false",
"viperCommentInvalidDiagnosticSeverityValue": "La directiva de comentario Viper debe ir seguida de \"=\" y un valor de true, false, error, warning, information o none.",
"viperCommentMissingDirective": "El comentario de Viper debe ir seguido de una directiva (basic o estricta) o de una regla de diagnóstico",
"viperCommentNotOnOwnLine": "Los comentarios de Viper utilizados para controlar los ajustes a nivel de archivo deben aparecer en su propia línea",
"viperCommentUnknownDiagnosticRule": "\"{rule}\" es una regla de diagnóstico desconocida para el comentario viper",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" es un valor no válido para el comentario viper; se espera true, false, error, warning, information o none.",
"viperCommentUnknownDirective": "\"{directive}\" es una directiva desconocida para el comentario viper; se esperaba \"strict\", \"standard\" o \"basic\"",
"readOnlyArgCount": "Se esperaba un único argumento de tipo después de \"ReadOnly\"",
"readOnlyNotInTypedDict": "\"ReadOnly\" no está permitido en este contexto",
"recursiveDefinition": "No se pudo determinar el tipo de \"{name}\" porque hace referencia a sí mismo.",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Llamada isinstance innecesaria; \"{testType}\" es nunca una instancia de \"{classType}\"",
"unnecessaryIsSubclassAlways": "Llamada de issubclass innecesaria; \"{testType}\" siempre es una subclase de \"{classType}\"",
"unnecessaryIsSubclassNever": "Llamada de issubclass innecesaria; \"{testType}\" nunca es una subclase de \"{classType}\"",
"unnecessaryPyrightIgnore": "Comentario \"# pyright: ignore\" innecesario",
"unnecessaryPyrightIgnoreRule": "Regla innecesaria \"# pyright: ignore\": \"{name}\"",
"unnecessaryViperIgnore": "Comentario \"# viper: ignore\" innecesario",
"unnecessaryViperIgnoreRule": "Regla innecesaria \"# viper: ignore\": \"{name}\"",
"unnecessaryTypeIgnore": "Comentario \"# type: ignore\" innecesario",
"unpackArgCount": "Se esperaba un único argumento de tipo después de \"Unpack\"",
"unpackExpectedTypeVarTuple": "Se esperaba TypeVarTuple o tuple como argumento de tipo para Unpack",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "La clase de Protocol debe ser @runtime_checkable para usarse con comprobaciones de instancia y clase",
"protocolSourceIsNotConcrete": "\"{sourceType}\" no es un tipo de clase concreto y no se puede asignar al tipo \"{destType}\"",
"protocolUnsafeOverlap": "Los atributos de \"{name}\" tienen los mismos nombres que el protocolo",
"pyrightCommentIgnoreTip": "Utilice \"# pyright: ignore[<diagnostic rules>]\" para suprimir el diagnóstico de una sola línea",
"viperCommentIgnoreTip": "Utilice \"# viper: ignore[<diagnostic rules>]\" para suprimir el diagnóstico de una sola línea",
"readOnlyAttribute": "El atributo \"{name}\" es de solo lectura",
"seeClassDeclaration": "Ver declaración de clase",
"seeDeclaration": "Ver declaración",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "La variable de type \"{variable}\" utilisée dans le Protocol générique \"{class}\" doit être contravariante",
"protocolVarianceCovariant": "La variable de type \"{variable}\" utilisée dans le Protocol générique \"{class}\" doit être covariante",
"protocolVarianceInvariant": "La variable de type \"{variable}\" utilisée dans le Protocol générique \"{class}\" doit être invariante",
"pyrightCommentInvalidDiagnosticBoolValue": "La directive de commentaire Pyright doit être suivie de « = » et d’une valeur true ou false",
"pyrightCommentInvalidDiagnosticSeverityValue": "La directive de commentaire Pyright doit être suivie de « = » et avoir la valeur true, false, error, warning, information ou none",
"pyrightCommentMissingDirective": "Le commentaire Pyright doit être suivi d’une directive (basic ou strict) ou d’une règle de diagnostic",
"pyrightCommentNotOnOwnLine": "Les commentaires Pyright utilisés pour contrôler les paramètres au niveau du fichier doivent apparaître sur leur propre ligne",
"pyrightCommentUnknownDiagnosticRule": "« {rule} » est une règle de diagnostic inconnue pour le commentaire pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "« {value} » n’est pas valide pour le commentaire pyright ; true, false, error, warning, information ou none attendu",
"pyrightCommentUnknownDirective": "« {directive} » est une directive inconnue pour le commentaire pyright ; « strict », « standard » ou « basic » attendu",
"viperCommentInvalidDiagnosticBoolValue": "La directive de commentaire Viper doit être suivie de « = » et d’une valeur true ou false",
"viperCommentInvalidDiagnosticSeverityValue": "La directive de commentaire Viper doit être suivie de « = » et avoir la valeur true, false, error, warning, information ou none",
"viperCommentMissingDirective": "Le commentaire Viper doit être suivi d’une directive (basic ou strict) ou d’une règle de diagnostic",
"viperCommentNotOnOwnLine": "Les commentaires Viper utilisés pour contrôler les paramètres au niveau du fichier doivent apparaître sur leur propre ligne",
"viperCommentUnknownDiagnosticRule": "« {rule} » est une règle de diagnostic inconnue pour le commentaire viper",
"viperCommentUnknownDiagnosticSeverityValue": "« {value} » n’est pas valide pour le commentaire viper ; true, false, error, warning, information ou none attendu",
"viperCommentUnknownDirective": "« {directive} » est une directive inconnue pour le commentaire viper ; « strict », « standard » ou « basic » attendu",
"readOnlyArgCount": "Attendu un seul argument de type après \"ReadOnly\"",
"readOnlyNotInTypedDict": "« ReadOnly » n’est pas autorisé dans ce contexte",
"recursiveDefinition": "Le type de \"{name}\" n'a pas pu être déterminé car il fait référence à lui-même",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Appel d’isinstance inutile; « {testType} » n est jamais une instance de « {classType} »",
"unnecessaryIsSubclassAlways": "Appel issubclass inutile ; \"{testType}\" est toujours une sous-classe de \"{classType}\"",
"unnecessaryIsSubclassNever": "Appel issubclass inutile; « {testType} » est toujours une sous-classe de « {classType} »",
"unnecessaryPyrightIgnore": "Commentaire \"# pyright: ignore\" inutile",
"unnecessaryPyrightIgnoreRule": "Règle inutile « # pyright: ignore » : « {name} »",
"unnecessaryViperIgnore": "Commentaire \"# viper: ignore\" inutile",
"unnecessaryViperIgnoreRule": "Règle inutile « # viper: ignore » : « {name} »",
"unnecessaryTypeIgnore": "Commentaire \"# type: ignore\" inutile",
"unpackArgCount": "Attendu un seul argument de type après \"Unpack\"",
"unpackExpectedTypeVarTuple": "TypeVarTuple ou tuple attendu en tant qu’argument de type pour Unpack",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "La classe de Protocol doit être @runtime_checkable à utiliser avec des vérifications d’instance et de classe",
"protocolSourceIsNotConcrete": "\"{sourceType}\" n'est pas un type de classe concret et ne peut pas être affecté au type \"{destType}\"",
"protocolUnsafeOverlap": "Les attributs de « {name} » ont les mêmes noms que le protocole",
"pyrightCommentIgnoreTip": "Utilisez « # pyright: ignore[<diagnostic rules>] » pour supprimer les diagnostics pour une seule ligne",
"viperCommentIgnoreTip": "Utilisez « # viper: ignore[<diagnostic rules>] » pour supprimer les diagnostics pour une seule ligne",
"readOnlyAttribute": "L’attribut « {name} » est en lecture seule",
"seeClassDeclaration": "Voir la déclaration de classe",
"seeDeclaration": "Voir la déclaration",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "La variabile di tipo \"{variable}\" usata in \"{class}\" Protocol generico deve essere controvariante",
"protocolVarianceCovariant": "La variabile di tipo \"{variable}\" usata in \"{class}\" Protocol generico deve essere covariante",
"protocolVarianceInvariant": "La variabile di tipo \"{variable}\" usata in \"{class}\" Protocol generico deve essere invariante",
"pyrightCommentInvalidDiagnosticBoolValue": "La direttiva di commento Pyright deve essere seguita da \"=\" e da un valore true o false",
"pyrightCommentInvalidDiagnosticSeverityValue": "La direttiva di commento Pyright deve essere seguita da \"=\" e da un valore true, false, error, warning, information o none",
"pyrightCommentMissingDirective": "Il commento Pyright deve essere seguito da una direttiva (basic o strict) o da una regola di diagnostica",
"pyrightCommentNotOnOwnLine": "I commenti Pyright usati per controllare le impostazioni a livello di file devono essere visualizzati nella propria riga",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\" è una regola di diagnostica sconosciuta per il commento pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" non è un valore valido per il commento pyright; previsto true, false, error, warning, information o none",
"pyrightCommentUnknownDirective": "\"{directive}\" è una direttiva sconosciuta per il commento pyright; previsto \"strict\", \"standard\" o \"basic\"",
"viperCommentInvalidDiagnosticBoolValue": "La direttiva di commento Viper deve essere seguita da \"=\" e da un valore true o false",
"viperCommentInvalidDiagnosticSeverityValue": "La direttiva di commento Viper deve essere seguita da \"=\" e da un valore true, false, error, warning, information o none",
"viperCommentMissingDirective": "Il commento Viper deve essere seguito da una direttiva (basic o strict) o da una regola di diagnostica",
"viperCommentNotOnOwnLine": "I commenti Viper usati per controllare le impostazioni a livello di file devono essere visualizzati nella propria riga",
"viperCommentUnknownDiagnosticRule": "\"{rule}\" è una regola di diagnostica sconosciuta per il commento viper",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" non è un valore valido per il commento viper; previsto true, false, error, warning, information o none",
"viperCommentUnknownDirective": "\"{directive}\" è una direttiva sconosciuta per il commento viper; previsto \"strict\", \"standard\" o \"basic\"",
"readOnlyArgCount": "Previsto un singolo argomento tipo dopo \"ReadOnly\"",
"readOnlyNotInTypedDict": "\"ReadOnly\" non consentito in questo contesto",
"recursiveDefinition": "Non è stato possibile determinare il tipo di \"{name}\" perché fa riferimento a se stesso",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Chiamata isinstance non necessaria; \"{testType}\" non è mai un'istanza di \"{classType}\"",
"unnecessaryIsSubclassAlways": "Chiamata issubclass non necessaria; \"{testType}\" è sempre una sottoclasse di \"{classType}\"",
"unnecessaryIsSubclassNever": "Chiamata issubclass non necessaria; \"{testType}\" non è mai una sottoclasse di \"{classType}\"",
"unnecessaryPyrightIgnore": "Commento \"# pyright: ignore\" non necessario",
"unnecessaryPyrightIgnoreRule": "Regola \"# pyright: ignore\" non necessaria: \"{name}\"",
"unnecessaryViperIgnore": "Commento \"# viper: ignore\" non necessario",
"unnecessaryViperIgnoreRule": "Regola \"# viper: ignore\" non necessaria: \"{name}\"",
"unnecessaryTypeIgnore": "Commento \"# type: ignore\" non necessario",
"unpackArgCount": "Previsto un singolo argomento di tipo dopo \"Unpack\"",
"unpackExpectedTypeVarTuple": "È previsto TypeVarTuple o tuple come argomento di tipo per Unpack",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "La classe di Protocol deve essere @runtime_checkable in modo che sia possibile usarla con i controlli di istanza e classe",
"protocolSourceIsNotConcrete": "\"{sourceType}\" non è un tipo di classe concreto e non può essere assegnato al tipo \"{destType}\"",
"protocolUnsafeOverlap": "Gli attributi di “{name}” hanno gli stessi nomi del protocollo",
"pyrightCommentIgnoreTip": "Usa \"# pyright: ignore[<diagnostic rules>]\" per eliminare la diagnostica per una singola riga",
"viperCommentIgnoreTip": "Usa \"# viper: ignore[<diagnostic rules>]\" per eliminare la diagnostica per una singola riga",
"readOnlyAttribute": "L'attributo \"{name}\" è di sola lettura",
"seeClassDeclaration": "Vedere la dichiarazione di classe",
"seeDeclaration": "Vedere la dichiarazione",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "ジェネリック Protocol \"{class}\" で使用される型変数 \"{variable}\" は反変である必要があります",
"protocolVarianceCovariant": "ジェネリック Protocol \"{class}\" で使用される型変数 \"{variable}\" は共変である必要があります",
"protocolVarianceInvariant": "ジェネリック Protocol \"{class}\" で使用される型変数 \"{variable}\" は不変である必要があります",
"pyrightCommentInvalidDiagnosticBoolValue": "Pyright コメント ディレクティブの後には \"=\" と値 true または false を指定する必要があります",
"pyrightCommentInvalidDiagnosticSeverityValue": "Pyright コメント ディレクティブの後に \"=\" と true、false、error、warning、information または none の値を指定する必要があります",
"pyrightCommentMissingDirective": "Pyright コメントの後にディレクティブ (basic または strict) または診断規則を指定する必要があります",
"pyrightCommentNotOnOwnLine": "ファイル レベルの設定を制御するために使用する Pyright コメントは、独自の行に表示する必要があります",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\" は pyright コメントの不明な診断規則です",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" は、pyright コメントの無効な値です。true、false、error、warning、information または none が必要です",
"pyrightCommentUnknownDirective": "\"{directive}\" は、pyright コメントの不明なディレクティブです。\"strict\"、\"standard\"、または \"basic\" が必要です",
"viperCommentInvalidDiagnosticBoolValue": "Viper コメント ディレクティブの後には \"=\" と値 true または false を指定する必要があります",
"viperCommentInvalidDiagnosticSeverityValue": "Viper コメント ディレクティブの後に \"=\" と true、false、error、warning、information または none の値を指定する必要があります",
"viperCommentMissingDirective": "Viper コメントの後にディレクティブ (basic または strict) または診断規則を指定する必要があります",
"viperCommentNotOnOwnLine": "ファイル レベルの設定を制御するために使用する Viper コメントは、独自の行に表示する必要があります",
"viperCommentUnknownDiagnosticRule": "\"{rule}\" は viper コメントの不明な診断規則です",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" は、viper コメントの無効な値です。true、false、error、warning、information または none が必要です",
"viperCommentUnknownDirective": "\"{directive}\" は、viper コメントの不明なディレクティブです。\"strict\"、\"standard\"、または \"basic\" が必要です",
"readOnlyArgCount": "\"ReadOnly\" の後に 1 つの型引数が必要です",
"readOnlyNotInTypedDict": "\"ReadOnly\" はこのコンテキストでは許可されていません",
"recursiveDefinition": "\"{name}\" の型は、それ自体を参照しているため、特定できませんでした",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "不要な isinstance 呼び出し; \"{testType}\" は\"{classType}\" のインスタンスであったことはありません",
"unnecessaryIsSubclassAlways": "不要な issubclass 呼び出し。\"{testType}\" は常に \"{classType}\" のサブクラスです",
"unnecessaryIsSubclassNever": "不要な issubclass 呼び出し; \"{testType}\" は \"{classType}\" のサブクラスであったことはありません",
"unnecessaryPyrightIgnore": "不要な \"# pyright: ignore\" コメント",
"unnecessaryPyrightIgnoreRule": "不要な \"# pyright: ignore\" ルール: \"{name}\"",
"unnecessaryViperIgnore": "不要な \"# viper: ignore\" コメント",
"unnecessaryViperIgnoreRule": "不要な \"# viper: ignore\" ルール: \"{name}\"",
"unnecessaryTypeIgnore": "不要な \"# type: ignore\" コメント",
"unpackArgCount": "\"Unpack\" の後に 1 つの型引数が必要です",
"unpackExpectedTypeVarTuple": "Unpack の型引数として TypeVarTuple または tuple が必要です",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "インスタンスとクラスのチェックで使用するには、Protocol クラスが @runtime_checkable である必要があります",
"protocolSourceIsNotConcrete": "\"{sourceType}\" は具象クラス型ではないため、型 \"{destType}\" に割り当てることはできません",
"protocolUnsafeOverlap": "\"{name}\" の属性の名前がプロトコルの名前と同じです",
"pyrightCommentIgnoreTip": "\"# pyright: ignore[<diagnostic rules>] を使用して 1 行の診断を抑制します",
"viperCommentIgnoreTip": "\"# viper: ignore[<diagnostic rules>] を使用して 1 行の診断を抑制します",
"readOnlyAttribute": "属性 \"{name}\" は読み取り専用です",
"seeClassDeclaration": "クラス宣言を参照してください",
"seeDeclaration": "宣言を参照してください",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "제네릭 Protocol \"{class}\"에 사용되는 형식 변수 \"{variable}\"은(는) 반공변이어야 합니다.",
"protocolVarianceCovariant": "제네릭 Protocol \"{class}\"에 사용되는 형식 변수 \"{variable}\"은(는) 공변(covariant)이어야 합니다.",
"protocolVarianceInvariant": "제네릭 Protocol \"{class}\"에 사용되는 형식 변수 \"{variable}\"은(는) 고정되어야 합니다.",
"pyrightCommentInvalidDiagnosticBoolValue": "Pyright 주석 지시문 뒤에는 \"=\"와 true 또는 false 값이 와야 합니다.",
"pyrightCommentInvalidDiagnosticSeverityValue": "Pyright 주석 지시문 뒤에는 \"=\"와 true, false, error, warning, information 또는 none 값이 와야 합니다.",
"pyrightCommentMissingDirective": "Pyright 메모 뒤에는 지시문(basic 또는 strict) 또는 진단 규칙이 있어야 합니다.",
"pyrightCommentNotOnOwnLine": "파일 수준 설정을 제어하는 데 사용되는Pyright 주석은 고유의 줄에 표시되어야 합니다.",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\"은(는) pyright 주석에 대한 알 수 없는 진단 규칙입니다.",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\"이(가) pyright 주석에 대해 잘못된 값입니다. true, false, error, warning, information 또는 none이 필요합니다.",
"pyrightCommentUnknownDirective": "\"{directive}\"은(는) pyright 주석에 대한 알 수 없는 지시문입니다. \"strict\", \"standard\" 또는 \"basic\"이 필요합니다.",
"viperCommentInvalidDiagnosticBoolValue": "Viper 주석 지시문 뒤에는 \"=\"와 true 또는 false 값이 와야 합니다.",
"viperCommentInvalidDiagnosticSeverityValue": "Viper 주석 지시문 뒤에는 \"=\"와 true, false, error, warning, information 또는 none 값이 와야 합니다.",
"viperCommentMissingDirective": "Viper 메모 뒤에는 지시문(basic 또는 strict) 또는 진단 규칙이 있어야 합니다.",
"viperCommentNotOnOwnLine": "파일 수준 설정을 제어하는 데 사용되는Viper 주석은 고유의 줄에 표시되어야 합니다.",
"viperCommentUnknownDiagnosticRule": "\"{rule}\"은(는) viper 주석에 대한 알 수 없는 진단 규칙입니다.",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\"이(가) viper 주석에 대해 잘못된 값입니다. true, false, error, warning, information 또는 none이 필요합니다.",
"viperCommentUnknownDirective": "\"{directive}\"은(는) viper 주석에 대한 알 수 없는 지시문입니다. \"strict\", \"standard\" 또는 \"basic\"이 필요합니다.",
"readOnlyArgCount": "‘ReadOnly‘ 뒤에는 단일 형식 인수가 필요합니다.",
"readOnlyNotInTypedDict": "이 컨텍스트에서는 \"ReadOnly\"를 사용할 수 없습니다.",
"recursiveDefinition": "‘{name}’ 형식이 스스로를 참조하므로 확인할 수 없습니다.",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "불필요한 isinstance 호출입니다. \"{testType}\"은(는) 항상 \"{classType}\"의 인스턴스입니다.",
"unnecessaryIsSubclassAlways": "불필요한 issubclass 호출입니다. ’{testType}‘은(는) 항상 ’{classType}‘의 하위 클래스입니다.",
"unnecessaryIsSubclassNever": "불필요한 issubclass 호출입니다. ’{testType}‘은(는) 항상 ’{classType}‘의 하위 클래스입니다.",
"unnecessaryPyrightIgnore": "불필요한 \"# pyright: ignore\" 메모입니다.",
"unnecessaryPyrightIgnoreRule": "불필요한 \"# pyright: ignore\" 규칙: \"{name}\"",
"unnecessaryViperIgnore": "불필요한 \"# viper: ignore\" 메모입니다.",
"unnecessaryViperIgnoreRule": "불필요한 \"# viper: ignore\" 규칙: \"{name}\"",
"unnecessaryTypeIgnore": "불필요한 \"# type: ignore\" 메모입니다.",
"unpackArgCount": "\"Unpack\" 뒤에는 단일 형식 인수가 필요합니다.",
"unpackExpectedTypeVarTuple": "Unpack에 대한 형식 인수로 TypeVarTuple 또는 tuple이 필요합니다.",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "인스턴스 및 클래스 검사와 함께 사용하려면 Protocol 클래스를 @runtime_checkable 합니다.",
"protocolSourceIsNotConcrete": "‘{sourceType}’은(는) 구체적인 클래스 형식이 아니므로 ‘{destType}’ 형식에 할당할 수 없습니다.",
"protocolUnsafeOverlap": "\"{name}\"의 특성은 프로토콜과 이름이 같습니다.",
"pyrightCommentIgnoreTip": "\"# pyright: ignore[<diagnostic rules>]\"을 사용하여 한 줄에 대한 진단을 표시하지 않습니다.",
"viperCommentIgnoreTip": "\"# viper: ignore[<diagnostic rules>]\"을 사용하여 한 줄에 대한 진단을 표시하지 않습니다.",
"readOnlyAttribute": "특성 \"{name}\"은(는) 읽기 전용입니다.",
"seeClassDeclaration": "클래스 선언 참조",
"seeDeclaration": "선언 참조",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "Zmienna typu „{variable}” używana w klasie ogólnej Protocol „{class}” powinna być kontrawariantna",
"protocolVarianceCovariant": "Zmienna typu „{variable}” używana w klasie ogólnej Protocol „{class}” powinna być kowariantna",
"protocolVarianceInvariant": "Zmienna typu „{variable}” używana w klasie ogólnego Protocol „{class}” powinna być niezmienna",
"pyrightCommentInvalidDiagnosticBoolValue": "Po dyrektywie komentarza Pyright musi następować znak „=” oraz wartość true lub false",
"pyrightCommentInvalidDiagnosticSeverityValue": "Po dyrektywie komentarza Pyright musi następować znak „=” oraz wartość true, false, error, warning, information lub none",
"pyrightCommentMissingDirective": "Po komentarzu Pyright musi następować dyrektywa (basic lub strict) lub reguła diagnostyczna",
"pyrightCommentNotOnOwnLine": "Komentarze Pyright używane do kontrolowania ustawień na poziomie plików muszą pojawiać się w oddzielnych wierszach",
"pyrightCommentUnknownDiagnosticRule": "Reguła „{rule}” jest nieznaną regułą diagnostyczną dla komentarza pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "Wartość „{value}” jest nieprawidłowa dla komentarza pyright; oczekiwano wartości: true, false, error, warning, information lub none",
"pyrightCommentUnknownDirective": "„{directive}” jest nieznaną dyrektywą dla komentarza pyright; oczekiwano „strict”, „standard” lub „basic”",
"viperCommentInvalidDiagnosticBoolValue": "Po dyrektywie komentarza Viper musi następować znak „=” oraz wartość true lub false",
"viperCommentInvalidDiagnosticSeverityValue": "Po dyrektywie komentarza Viper musi następować znak „=” oraz wartość true, false, error, warning, information lub none",
"viperCommentMissingDirective": "Po komentarzu Viper musi następować dyrektywa (basic lub strict) lub reguła diagnostyczna",
"viperCommentNotOnOwnLine": "Komentarze Viper używane do kontrolowania ustawień na poziomie plików muszą pojawiać się w oddzielnych wierszach",
"viperCommentUnknownDiagnosticRule": "Reguła „{rule}” jest nieznaną regułą diagnostyczną dla komentarza viper",
"viperCommentUnknownDiagnosticSeverityValue": "Wartość „{value}” jest nieprawidłowa dla komentarza viper; oczekiwano wartości: true, false, error, warning, information lub none",
"viperCommentUnknownDirective": "„{directive}” jest nieznaną dyrektywą dla komentarza viper; oczekiwano „strict”, „standard” lub „basic”",
"readOnlyArgCount": "Oczekiwano jednego argumentu typu po wartości „ReadOnly”",
"readOnlyNotInTypedDict": "Element „ReadOnly” jest niedozwolony w tym kontekście",
"recursiveDefinition": "Nie można określić typu „{name}”, ponieważ odwołuje się on do samego siebie",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Niepotrzebne wywołanie funkcji isinstance; „{testType}” nigdy nie jest instancją „{classType}”",
"unnecessaryIsSubclassAlways": "Niepotrzebne wywołanie „issubclass”; „{testType}” jest zawsze podklasą klasy „{classType}”",
"unnecessaryIsSubclassNever": "Niepotrzebne wywołanie funkcji issubclass; „{testType}” nigdy nie jest podklasą „{classType}”",
"unnecessaryPyrightIgnore": "Niepotrzebny komentarz „# pyright: ignore”",
"unnecessaryPyrightIgnoreRule": "Niepotrzebna reguła „# pyright: ignore”: „{name}”",
"unnecessaryViperIgnore": "Niepotrzebny komentarz „# viper: ignore”",
"unnecessaryViperIgnoreRule": "Niepotrzebna reguła „# viper: ignore”: „{name}”",
"unnecessaryTypeIgnore": "Niepotrzebny komentarz „# type: ignore”",
"unpackArgCount": "Oczekiwano jednego argumentu typu po wartości „Unpack”",
"unpackExpectedTypeVarTuple": "Oczekiwano typu TypeVarTuple lub tuple jako argumentu typu dla elementu Unpack",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Klasa Protocol musi być @runtime_checkable, aby mogła być używana z kontrolami wystąpień i klas",
"protocolSourceIsNotConcrete": "„{sourceType}” nie jest typem specyficznej klasy i nie można go przypisać do typu „{destType}”",
"protocolUnsafeOverlap": "Atrybuty „{name}” mają takie same nazwy jak protokół",
"pyrightCommentIgnoreTip": "Użyj polecenia „# pyright: ignore[<diagnostic rules>]”, aby wyłączyć diagnostykę dla pojedynczego wiersza",
"viperCommentIgnoreTip": "Użyj polecenia „# viper: ignore[<diagnostic rules>]”, aby wyłączyć diagnostykę dla pojedynczego wiersza",
"readOnlyAttribute": "Atrybut „{name}” jest tylko do odczytu",
"seeClassDeclaration": "Zobacz deklarację klasy",
"seeDeclaration": "Zobacz deklarację",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "A variável de tipo \"{variable}\" usada na \"{class}\" Protocol genérica deve ser contravariante",
"protocolVarianceCovariant": "A variável de tipo \"{variable}\" usada na \"{class}\" Protocol genérica deve ser covariante",
"protocolVarianceInvariant": "A variável de tipo \"{variable}\" usada na \"{class}\" Protocol genérica deve ser invariável",
"pyrightCommentInvalidDiagnosticBoolValue": "A diretiva de comentário Pyright deve ser seguida por \"=\" e um valor true ou false",
"pyrightCommentInvalidDiagnosticSeverityValue": "A diretiva de comentário Pyright deve ser seguida por \"=\" e um valor de true, false, error, warning, information ou none",
"pyrightCommentMissingDirective": "O comentário Pyright deve ser seguido por uma diretiva (basic ou strict) ou uma regra de diagnóstico",
"pyrightCommentNotOnOwnLine": "Comentários Pyright usados para controlar as configurações de nível de arquivo devem aparecer em sua própria linha",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\" é uma regra de diagnóstico desconhecida para o comentário pyright",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" é um valor inválido para o comentário pyright. true, false, error, warning, information ou none esperados.",
"pyrightCommentUnknownDirective": "\"{directive}\" é uma diretiva desconhecida para o comentário pyright; esperava-se \"strict\", \"standard\" ou \"basic\"",
"viperCommentInvalidDiagnosticBoolValue": "A diretiva de comentário Viper deve ser seguida por \"=\" e um valor true ou false",
"viperCommentInvalidDiagnosticSeverityValue": "A diretiva de comentário Viper deve ser seguida por \"=\" e um valor de true, false, error, warning, information ou none",
"viperCommentMissingDirective": "O comentário Viper deve ser seguido por uma diretiva (basic ou strict) ou uma regra de diagnóstico",
"viperCommentNotOnOwnLine": "Comentários Viper usados para controlar as configurações de nível de arquivo devem aparecer em sua própria linha",
"viperCommentUnknownDiagnosticRule": "\"{rule}\" é uma regra de diagnóstico desconhecida para o comentário viper",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" é um valor inválido para o comentário viper. true, false, error, warning, information ou none esperados.",
"viperCommentUnknownDirective": "\"{directive}\" é uma diretiva desconhecida para o comentário viper; esperava-se \"strict\", \"standard\" ou \"basic\"",
"readOnlyArgCount": "Argumento de tipo único esperado após \"ReadOnly\"",
"readOnlyNotInTypedDict": "\"ReadOnly\" não é permitido neste contexto",
"recursiveDefinition": "Não foi possível determinar o tipo de \"{name}\" porque ele refere-se a si mesmo",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Chamada de isinstance desnecessária; '{testType}' nunca é uma instância de '{classType}'",
"unnecessaryIsSubclassAlways": "Chamada issubclass desnecessária. \"{testType}\" é sempre uma subclasse de \"{classType}\"",
"unnecessaryIsSubclassNever": "Chamada issubclass desnecessária; '{testType}' nunca é uma subclasse de '{classType}'",
"unnecessaryPyrightIgnore": "Comentário desnecessário \"# pyright: ignore\"",
"unnecessaryPyrightIgnoreRule": "Regra desnecessária \"# pyright: ignore\": \"{name}\"",
"unnecessaryViperIgnore": "Comentário desnecessário \"# viper: ignore\"",
"unnecessaryViperIgnoreRule": "Regra desnecessária \"# viper: ignore\": \"{name}\"",
"unnecessaryTypeIgnore": "Comentário \"# type: ignore\" desnecessário",
"unpackArgCount": "Argumento de tipo único esperado após \"Unpack\"",
"unpackExpectedTypeVarTuple": "TypeVarTuple ou tuple esperado como argumento de tipo para Unpack",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "A classe do Protocol deve ser @runtime_checkable para ser usada com verificações de instância e de classe",
"protocolSourceIsNotConcrete": "\"{sourceType}\" não é um tipo de classe concreta e não pode ser atribuído ao tipo \"{destType}\"",
"protocolUnsafeOverlap": "Os atributos de \"{name}\" têm os mesmos nomes que o protocolo",
"pyrightCommentIgnoreTip": "Use \"# pyright: ignore[<diagnostic rules>]\" para suprimir o diagnóstico de uma única linha",
"viperCommentIgnoreTip": "Use \"# viper: ignore[<diagnostic rules>]\" para suprimir o diagnóstico de uma única linha",
"readOnlyAttribute": "O atributo \"{name}\" é somente leitura",
"seeClassDeclaration": "Consulte a declaração de classe",
"seeDeclaration": "Consulte a declaração",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "[B4htZ][นั้Tÿpë værïæþlë \"{værïæþlë}\" µsëð ïñ gëñërïç Protocol \"{çlæss}\" shøµlð þë çøñtræværïæñtẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"protocolVarianceCovariant": "[Hcnn5][นั้Tÿpë værïæþlë \"{værïæþlë}\" µsëð ïñ gëñërïç Protocol \"{çlæss}\" shøµlð þë çøværïæñtẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"protocolVarianceInvariant": "[o8oB7][นั้Tÿpë værïæþlë \"{værïæþlë}\" µsëð ïñ gëñërïç Protocol \"{çlæss}\" shøµlð þë ïñværïæñtẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"pyrightCommentInvalidDiagnosticBoolValue": "[eaJY0][นั้Pyright çømmëñt ðïrëçtïvë mµst þë følløwëð þÿ \"=\" æñð æ vælµë øf true ør falseẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪นั้ढूँ]",
"pyrightCommentInvalidDiagnosticSeverityValue": "[2YA7K][นั้Pyright çømmëñt ðïrëçtïvë mµst þë følløwëð þÿ \"=\" æñð æ vælµë øf true, false, error, warning, information, ør noneẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"pyrightCommentMissingDirective": "[yy6rB][นั้Pyright çømmëñt mµst þë følløwëð þÿ æ ðïrëçtïvë (basic ør strict) ør æ ðïægñøstïç rµlëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"pyrightCommentNotOnOwnLine": "[mM2bV][นั้Pyright çømmëñts µsëð tø çøñtrøl fïlë-lëvël sëttïñgs mµst æppëær øñ thëïr øwñ lïñëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂนั้ढूँ]",
"pyrightCommentUnknownDiagnosticRule": "[DFAZp][นั้\"{rµlë}\" ïs æñ µñkñøwñ ðïægñøstïç rµlë før pyright çømmëñtẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]",
"pyrightCommentUnknownDiagnosticSeverityValue": "[Tgt0Y][นั้\"{vælµë}\" ïs ïñvælïð vælµë før pyright çømmëñt; ëxpëçtëð true, false, error, warning, information, ør noneẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまนั้ढूँ]",
"pyrightCommentUnknownDirective": "[HD6T4][นั้\"{ðïrëçtïvë}\" ïs æñ µñkñøwñ ðïrëçtïvë før pyright çømmëñt; ëxpëçtëð \"strict\", \"standard\", ør \"basic\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृนั้ढूँ]",
"viperCommentInvalidDiagnosticBoolValue": "[eaJY0][นั้Viper çømmëñt ðïrëçtïvë mµst þë følløwëð þÿ \"=\" æñð æ vælµë øf true ør falseẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪นั้ढूँ]",
"viperCommentInvalidDiagnosticSeverityValue": "[2YA7K][นั้Viper çømmëñt ðïrëçtïvë mµst þë følløwëð þÿ \"=\" æñð æ vælµë øf true, false, error, warning, information, ør noneẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"viperCommentMissingDirective": "[yy6rB][นั้Viper çømmëñt mµst þë følløwëð þÿ æ ðïrëçtïvë (basic ør strict) ør æ ðïægñøstïç rµlëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"viperCommentNotOnOwnLine": "[mM2bV][นั้Viper çømmëñts µsëð tø çøñtrøl fïlë-lëvël sëttïñgs mµst æppëær øñ thëïr øwñ lïñëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂนั้ढूँ]",
"viperCommentUnknownDiagnosticRule": "[DFAZp][นั้\"{rµlë}\" ïs æñ µñkñøwñ ðïægñøstïç rµlë før viper çømmëñtẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]",
"viperCommentUnknownDiagnosticSeverityValue": "[Tgt0Y][นั้\"{vælµë}\" ïs ïñvælïð vælµë før viper çømmëñt; ëxpëçtëð true, false, error, warning, information, ør noneẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまนั้ढूँ]",
"viperCommentUnknownDirective": "[HD6T4][นั้\"{ðïrëçtïvë}\" ïs æñ µñkñøwñ ðïrëçtïvë før viper çømmëñt; ëxpëçtëð \"strict\", \"standard\", ør \"basic\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृนั้ढूँ]",
"readOnlyArgCount": "[B1Erm][นั้Ëxpëçtëð æ sïñglë tÿpë ærgµmëñt æftër \"ReadOnly\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂนั้ढूँ]",
"readOnlyNotInTypedDict": "[xJrLN][นั้\"ReadOnly\" ïs ñøt ælløwëð ïñ thïs çøñtëxtẤğ倪İЂҰक्र्तिृまẤğนั้ढूँ]",
"recursiveDefinition": "[G3UUN][นั้Tÿpë øf \"{ñæmë}\" çøµlð ñøt þë ðëtërmïñëð þëçæµsë ït rëfërs tø ïtsëlfẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृนั้ढूँ]",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "[60nSE][นั้Üññëçëssærÿ isinstance çæll; \"{tëstTÿpë}\" ïs ñëvër æñ ïñstæñçë øf \"{çlæssTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"unnecessaryIsSubclassAlways": "[BzHtx][นั้Üññëçëssærÿ issubclass çæll; \"{tëstTÿpë}\" ïs ælwæÿs æ sµþçlæss øf \"{çlæssTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"unnecessaryIsSubclassNever": "[bOMnf][นั้Üññëçëssærÿ issubclass çæll; \"{tëstTÿpë}\" ïs ñëvër æ sµþçlæss øf \"{çlæssTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪นั้ढूँ]",
"unnecessaryPyrightIgnore": "[7QhdX][นั้Üññëçëssærÿ \"# pyright: ignore\" çømmëñtẤğ倪İЂҰक्र्तिृまẤğนั้ढूँ]",
"unnecessaryPyrightIgnoreRule": "[0ESoQ][นั้Üññëçëssærÿ \"# pyright: ignore\" rµlë: \"{ñæmë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"unnecessaryViperIgnore": "[7QhdX][นั้Üññëçëssærÿ \"# viper: ignore\" çømmëñtẤğ倪İЂҰक्र्तिृまẤğนั้ढूँ]",
"unnecessaryViperIgnoreRule": "[0ESoQ][นั้Üññëçëssærÿ \"# viper: ignore\" rµlë: \"{ñæmë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"unnecessaryTypeIgnore": "[IoWr9][นั้Üññëçëssærÿ \"# type: ignore\" çømmëñtẤğ倪İЂҰक्र्तिृまนั้ढूँ]",
"unpackArgCount": "[bkAT1][นั้Ëxpëçtëð æ sïñglë tÿpë ærgµmëñt æftër \"Unpack\"Ấğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"unpackExpectedTypeVarTuple": "[CWX8o][นั้Ëxpëçtëð TypeVarTuple ør tuple æs tÿpë ærgµmëñt før UnpackẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "[c9ewn][นั้Protocol çlæss mµst þë @runtime_checkable tø þë µsëð wïth ïñstæñçë æñð çlæss çhëçksẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂนั้ढूँ]",
"protocolSourceIsNotConcrete": "[DnLrN][นั้\"{søµrçëTÿpë}\" ïs ñøt æ çøñçrëtë çlæss tÿpë æñð çæññøt þë æssïgñëð tø tÿpë \"{ðëstTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्นั้ढूँ]",
"protocolUnsafeOverlap": "[fKiUM][นั้Ættrïþµtës øf \"{ñæmë}\" hævë thë sæmë ñæmës æs thë prøtøçølẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]",
"pyrightCommentIgnoreTip": "[raFZN][นั้Üsë \"# pyright: ignore[<diagnostic rules>]\" tø sµpprëss ðïægñøstïçs før æ sïñglë lïñëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"viperCommentIgnoreTip": "[raFZN][นั้Üsë \"# viper: ignore[<diagnostic rules>]\" tø sµpprëss ðïægñøstïçs før æ sïñglë lïñëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"readOnlyAttribute": "[k9waY][นั้Ættrïþµtë \"{ñæmë}\" ïs rëæð-øñlÿẤğ倪İЂҰक्र्तिृนั้ढूँ]",
"seeClassDeclaration": "[8sx7n][นั้§ëë çlæss ðëçlærætïøñẤğ倪İЂҰक्นั้ढूँ]",
"seeDeclaration": "[K0X6p][นั้§ëë ðëçlærætïøñẤğ倪İЂҰนั้ढूँ]",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "Переменная типа \"{variable}\", используемая в универсальном Protocol \"{class}\", должна быть контравариантной.",
"protocolVarianceCovariant": "Переменная типа \"{variable}\", используемая в универсальном Protocol \"{class}\", должна быть ковариантной",
"protocolVarianceInvariant": "Переменная типа \"{variable}\", используемая в универсальном Protocol \"{class}\", должна быть инвариантной",
"pyrightCommentInvalidDiagnosticBoolValue": "За директивой комментария Pyright должно следовать \"=\" и значение true или false",
"pyrightCommentInvalidDiagnosticSeverityValue": "За директивой комментария Pyright должно следовать \"=\" и одно из следующих значений: true, false, error, warning, information или none",
"pyrightCommentMissingDirective": "После комментария Pyright должна следовать директива (basic или strict) или правило диагностики",
"pyrightCommentNotOnOwnLine": "Комментарии Pyright, используемые для управления параметрами на уровне файлов, должны располагаться в отдельной строке",
"pyrightCommentUnknownDiagnosticRule": "Правило диагностики \"{rule}\" для комментария pyright неизвестно",
"pyrightCommentUnknownDiagnosticSeverityValue": "Значение \"{value}\" недопустимо для комментария pyright; ожидается одно из значений true, false, error, warning, information или none",
"pyrightCommentUnknownDirective": "\"{directive}\" — это неизвестная директива для комментария pyright; ожидается \"strict\", \"standard\" или \"basic\"",
"viperCommentInvalidDiagnosticBoolValue": "За директивой комментария Viper должно следовать \"=\" и значение true или false",
"viperCommentInvalidDiagnosticSeverityValue": "За директивой комментария Viper должно следовать \"=\" и одно из следующих значений: true, false, error, warning, information или none",
"viperCommentMissingDirective": "После комментария Viper должна следовать директива (basic или strict) или правило диагностики",
"viperCommentNotOnOwnLine": "Комментарии Viper, используемые для управления параметрами на уровне файлов, должны располагаться в отдельной строке",
"viperCommentUnknownDiagnosticRule": "Правило диагностики \"{rule}\" для комментария viper неизвестно",
"viperCommentUnknownDiagnosticSeverityValue": "Значение \"{value}\" недопустимо для комментария viper; ожидается одно из значений true, false, error, warning, information или none",
"viperCommentUnknownDirective": "\"{directive}\" — это неизвестная директива для комментария viper; ожидается \"strict\", \"standard\" или \"basic\"",
"readOnlyArgCount": "Ожидается один аргумент типа после \"ReadOnly\"",
"readOnlyNotInTypedDict": "Использование \"ReadOnly\" в этом контексте не допускается",
"recursiveDefinition": "Не удалось определить тип \"{name}\", так как он ссылается на себя",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Ненужный вызов isinstance; \"{testType}\" никогда не является экземпляром \"{classType}\"",
"unnecessaryIsSubclassAlways": "Ненужный вызов issubclass. \"{testType}\" всегда является подклассом \"{classType}\"",
"unnecessaryIsSubclassNever": "Ненужный вызов issubclass; \"{testType}\" никогда не является подклассом \"{classType}\"",
"unnecessaryPyrightIgnore": "Ненужный комментарий \"# pyright: ignore\"",
"unnecessaryPyrightIgnoreRule": "Ненужное правило \"# pyright: ignore\": \"{name}\"",
"unnecessaryViperIgnore": "Ненужный комментарий \"# viper: ignore\"",
"unnecessaryViperIgnoreRule": "Ненужное правило \"# viper: ignore\": \"{name}\"",
"unnecessaryTypeIgnore": "Ненужный комментарий \"# type: ignore\"",
"unpackArgCount": "Ожидается один аргумент типа после \"Unpack\"",
"unpackExpectedTypeVarTuple": "В качестве аргумента типа для Unpack ожидается элемент TypeVarTuple или tuple",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Класс Protocol должен быть @runtime_checkable, чтобы его можно было использовать при проверках экземпляров и классов",
"protocolSourceIsNotConcrete": "\"{sourceType}\" не является конкретным типом класса и не может быть присвоен типу \"{destType}\"",
"protocolUnsafeOverlap": "Атрибуты \"{name}\" используют те же имена, что и протокол",
"pyrightCommentIgnoreTip": "Для подавления диагностики в одной строке используйте конструкцию \"# pyright: ignore[<diagnostic rules>]\"",
"viperCommentIgnoreTip": "Для подавления диагностики в одной строке используйте конструкцию \"# viper: ignore[<diagnostic rules>]\"",
"readOnlyAttribute": "Атрибут \"{name}\" доступен только для чтения",
"seeClassDeclaration": "См. объявление класса",
"seeDeclaration": "См. объявление",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "Genel Protocol \"{class}\" için kullanılan \"{variable}\" tür değişkeni, değişken karşıtı olmalıdır",
"protocolVarianceCovariant": "Genel Protocol \"{class}\" için kullanılan \"{variable}\" tür değişkeni, birlikte değişen olmalıdır",
"protocolVarianceInvariant": "Genel Protocol \"{class}\" için kullanılan \"{variable}\" tür değişkeni sabit olmalıdır",
"pyrightCommentInvalidDiagnosticBoolValue": "Pyright açıklama yönergesinden sonra \"=\" ve true veya false değeri olmalıdır",
"pyrightCommentInvalidDiagnosticSeverityValue": "Pyright açıklama yönergesinden sonra \"=\" ve true, false, error, warning, information veya none değeri girilmelidir",
"pyrightCommentMissingDirective": "Pyright comment must be followed by a directive (basic or strict) or a diagnostic rule",
"pyrightCommentNotOnOwnLine": "Pyright comments used to control file-level settings must appear on their own line",
"pyrightCommentUnknownDiagnosticRule": "\"{rule}\", pyright açıklaması için bilinmeyen bir tanılama kuralı",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\" pyright açıklaması için geçersiz değer; true, false, error, warning, information veya none bekleniyordu",
"pyrightCommentUnknownDirective": "\"{directive}\", pyright açıklaması için bilinmeyen bir yönergedir; \"strict\", \"standard\" veya \"basic\" bekleniyordu",
"viperCommentInvalidDiagnosticBoolValue": "Viper açıklama yönergesinden sonra \"=\" ve true veya false değeri olmalıdır",
"viperCommentInvalidDiagnosticSeverityValue": "Viper açıklama yönergesinden sonra \"=\" ve true, false, error, warning, information veya none değeri girilmelidir",
"viperCommentMissingDirective": "Viper comment must be followed by a directive (basic or strict) or a diagnostic rule",
"viperCommentNotOnOwnLine": "Viper comments used to control file-level settings must appear on their own line",
"viperCommentUnknownDiagnosticRule": "\"{rule}\", viper açıklaması için bilinmeyen bir tanılama kuralı",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\" viper açıklaması için geçersiz değer; true, false, error, warning, information veya none bekleniyordu",
"viperCommentUnknownDirective": "\"{directive}\", viper açıklaması için bilinmeyen bir yönergedir; \"strict\", \"standard\" veya \"basic\" bekleniyordu",
"readOnlyArgCount": "\"ReadOnly\" sonrasında tek bir tür bağımsız değişken bekleniyordu",
"readOnlyNotInTypedDict": "Bu bağlamda \"ReadOnly\" kullanımına izin verilmiyor",
"recursiveDefinition": "Kendine başvurduğundan \"{name}\" türü belirlenemedi",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "Gereksiz isinstance çağrısı; \"{testType}\" asla bir \"{classType}\" örneği değildir",
"unnecessaryIsSubclassAlways": "Gereksiz issubclass çağrısı; \"{testType}\" her zaman \"{classType}\" sınıf türünün bir alt sınıfıdır",
"unnecessaryIsSubclassNever": "Gereksiz issubclass çağrısı; \"{testType}\" asla \"{classType}\" sınıf türünün bir alt sınıfı değildir",
"unnecessaryPyrightIgnore": "Gereksiz \"# pyright: ignore\" açıklaması",
"unnecessaryPyrightIgnoreRule": "\"# pyright: ignore\" rule: \"{name}\" gereksiz",
"unnecessaryViperIgnore": "Gereksiz \"# viper: ignore\" açıklaması",
"unnecessaryViperIgnoreRule": "\"# viper: ignore\" rule: \"{name}\" gereksiz",
"unnecessaryTypeIgnore": "Unnecessary \"# type: ignore\" comment",
"unpackArgCount": "\"Unpack\" sonrasında tek bir tür bağımsız değişken bekleniyordu",
"unpackExpectedTypeVarTuple": "Unpack için tür bağımsız değişkeni olarak TypeVarTuple veya tuple bekleniyordu",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Protocol sınıfının örnekle ve sınıf denetimleriyle birlikte kullanılabilmesi için @runtime_checkable olması gerekir",
"protocolSourceIsNotConcrete": "\"{sourceType}\" somut bir sınıf türü değil ve \"{destType}\" türüne atanamaz",
"protocolUnsafeOverlap": "\"{name}\" öznitelikleri protokolle aynı adlara sahip",
"pyrightCommentIgnoreTip": "Tek bir satırda tanılamayı durdurmak için \"# pyright: ignore[<diagnostic rules>]\" kullanın",
"viperCommentIgnoreTip": "Tek bir satırda tanılamayı durdurmak için \"# viper: ignore[<diagnostic rules>]\" kullanın",
"readOnlyAttribute": "\"{name}\" özniteliği salt okunur",
"seeClassDeclaration": "Sınıf bildirimine bakın",
"seeDeclaration": "Bildirime bakın",
@@ -429,13 +429,13 @@
"protocolVarianceContravariant": "泛型 Protocol \"{class}\" 中使用的类型变量 \"{variable}\" 应为反变量",
"protocolVarianceCovariant": "泛型 Protocol \"{class}\" 中使用的类型变量 \"{variable}\" 应为共变量",
"protocolVarianceInvariant": "泛型 Protocol \"{class}\" 中使用的类型变量 \"{variable}\" 应为固定变量",
"pyrightCommentInvalidDiagnosticBoolValue": "Pyright 注释指令后面必须跟有“=”和 true 或 false 值",
"pyrightCommentInvalidDiagnosticSeverityValue": "Pyright 注释指令后面必须跟有“=”,并且值为 true、false、error、warning、information 或 none",
"pyrightCommentMissingDirective": "Pyright 注释后面必须是指令(basic 或 strict)或诊断规则",
"pyrightCommentNotOnOwnLine": "用于控制文件级设置的 Pyright 注释必须显示在其自己的行上",
"pyrightCommentUnknownDiagnosticRule": "“{rule}”是 pyright 注释的未知诊断规则",
"pyrightCommentUnknownDiagnosticSeverityValue": "\"{value}\"是 pyright 注释的无效值;应为 true、false、error、warning、information 或 none",
"pyrightCommentUnknownDirective": "“{directive}”是 pyright 注释的未知指令;应为 \"strict\"、\"standard\" 或 \"basic\"",
"viperCommentInvalidDiagnosticBoolValue": "Viper 注释指令后面必须跟有“=”和 true 或 false 值",
"viperCommentInvalidDiagnosticSeverityValue": "Viper 注释指令后面必须跟有“=”,并且值为 true、false、error、warning、information 或 none",
"viperCommentMissingDirective": "Viper 注释后面必须是指令(basic 或 strict)或诊断规则",
"viperCommentNotOnOwnLine": "用于控制文件级设置的 Viper 注释必须显示在其自己的行上",
"viperCommentUnknownDiagnosticRule": "“{rule}”是 viper 注释的未知诊断规则",
"viperCommentUnknownDiagnosticSeverityValue": "\"{value}\"是 viper 注释的无效值;应为 true、false、error、warning、information 或 none",
"viperCommentUnknownDirective": "“{directive}”是 viper 注释的未知指令;应为 \"strict\"、\"standard\" 或 \"basic\"",
"readOnlyArgCount": "“ReadOnly”后应为单个类型参数",
"readOnlyNotInTypedDict": "此上下文中不允许使用“ReadOnly”",
"recursiveDefinition": "无法确定“{name}”的类型,因为它引用其自身",
@@ -625,8 +625,8 @@
"unnecessaryIsInstanceNever": "不必要的 isinstance 调用;“{testType}”始终不是“{classType}”的实例",
"unnecessaryIsSubclassAlways": "不必要的 issubclass 调用;“{testType}”始终是“{classType}”的子类",
"unnecessaryIsSubclassNever": "不必要的 issubclass 调用;“{testType}”始终不是“{classType}”的子类",
"unnecessaryPyrightIgnore": "不必要的 \"# pyright: ignore\" 注释",
"unnecessaryPyrightIgnoreRule": "不必要的 \"# pyright: ignore\"规则: \"{name}\"",
"unnecessaryViperIgnore": "不必要的 \"# viper: ignore\" 注释",
"unnecessaryViperIgnoreRule": "不必要的 \"# viper: ignore\"规则: \"{name}\"",
"unnecessaryTypeIgnore": "不必要的 \"# type: ignore\" 注释",
"unpackArgCount": "\"Unpack\"后应为单个类型参数",
"unpackExpectedTypeVarTuple": "Unpack 预期接收 TypeVarTuple 或 tuple 作为类型参数",
@@ -786,7 +786,7 @@
"protocolRequiresRuntimeCheckable": "Protocol 类必须为 @runtime_checkable 才能用于实例和类检查",
"protocolSourceIsNotConcrete": "“{sourceType}”不是具体类类型,无法分配给类型“{destType}”",
"protocolUnsafeOverlap": "“{name}”的属性与协议具有相同的名称",
"pyrightCommentIgnoreTip": "使用 \"# pyright: ignore[<diagnostic rules>]\" 抑制单行诊断",
"viperCommentIgnoreTip": "使用 \"# viper: ignore[<diagnostic rules>]\" 抑制单行诊断",
"readOnlyAttribute": "属性“{name}”为只读",
"seeClassDeclaration": "查看类声明",
"seeDeclaration": "参见声明",
Loaded 100 of 589 files, more files were not shown because too many files have changed in this diff. Show more