added readme
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[unstable]
|
||||
build-std = ["core", "compiler_builtins"]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[build]
|
||||
target = "x86_64-unknown-none"
|
||||
|
||||
[target.x86_64-unknown-none]
|
||||
rustflags = ["-Clink-arg=-Tsrc/linker.ld", "-Crelocation-model=static"]
|
||||
@@ -0,0 +1 @@
|
||||
/target
|
||||
Generated
+53
@@ -0,0 +1,53 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a"
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.9.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13f6a8a495d2f93fe3d6eb3a224f9aa749a63cfd746ed03eb5ddcbd00ade7d8f"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
|
||||
|
||||
[[package]]
|
||||
name = "wordleos"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x86_64"
|
||||
version = "0.14.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"rustversion",
|
||||
"volatile",
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "wordleos"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bootloader = "0.9"
|
||||
x86_64 = "0.14"
|
||||
+475
@@ -0,0 +1,475 @@
|
||||
CPU Reset (CPU 0)
|
||||
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00060fb1
|
||||
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
|
||||
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0000 00000000 0000ffff 00009300
|
||||
CS =f000 ffff0000 0000ffff 00009b00
|
||||
SS =0000 00000000 0000ffff 00009300
|
||||
DS =0000 00000000 0000ffff 00009300
|
||||
FS =0000 00000000 0000ffff 00009300
|
||||
GS =0000 00000000 0000ffff 00009300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 0000ffff
|
||||
IDT= 00000000 0000ffff
|
||||
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
|
||||
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
|
||||
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
|
||||
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
|
||||
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
|
||||
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
|
||||
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
|
||||
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
|
||||
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
|
||||
CPU Reset (CPU 0)
|
||||
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00060fb1
|
||||
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
|
||||
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0000 00000000 0000ffff 00009300
|
||||
CS =f000 ffff0000 0000ffff 00009b00
|
||||
SS =0000 00000000 0000ffff 00009300
|
||||
DS =0000 00000000 0000ffff 00009300
|
||||
FS =0000 00000000 0000ffff 00009300
|
||||
GS =0000 00000000 0000ffff 00009300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 0000ffff
|
||||
IDT= 00000000 0000ffff
|
||||
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
|
||||
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
|
||||
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
|
||||
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
|
||||
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
|
||||
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
|
||||
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
|
||||
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
|
||||
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
|
||||
SMM: enter
|
||||
EAX=00000000 EBX=00000000 ECX=02000000 EDX=02000628
|
||||
ESI=0000000b EDI=02000000 EBP=06feb0e0 ESP=00006d5c
|
||||
EIP=000ebede EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=ffffffff CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=00000000 EBX=00000000 ECX=02000000 EDX=02000628
|
||||
ESI=0000000b EDI=02000000 EBP=06feb0e0 ESP=00006d5c
|
||||
EIP=000ebede EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=00006cff
|
||||
ESI=00006cb8 EDI=06ffee71 EBP=00006c78 ESP=00006c78
|
||||
EIP=00007d2a EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 008f9300
|
||||
CS =f000 000f0000 ffffffff 008f9b00
|
||||
SS =0000 00000000 ffffffff 008f9300
|
||||
DS =0000 00000000 ffffffff 008f9300
|
||||
FS =0000 00000000 ffffffff 008f9300
|
||||
GS =0000 00000000 ffffffff 008f9300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00006c78 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=00006cff
|
||||
ESI=00006cb8 EDI=06ffee71 EBP=00006c78 ESP=00006c78
|
||||
EIP=000f7d2d EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=06fffe88
|
||||
ESI=000e9780 EDI=06ffee71 EBP=00006c78 ESP=00006c78
|
||||
EIP=000f7d44 EFL=00000012 [----A--] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000008 CCD=00006c64 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=06fffe88
|
||||
ESI=000e9780 EDI=06ffee71 EBP=00006c78 ESP=00006c78
|
||||
EIP=00007d47 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =0000 00000000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000004 CCD=00000001 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=000069a2 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=00007d2a EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 008f9300
|
||||
CS =f000 000f0000 ffffffff 008f9b00
|
||||
SS =0000 00000000 ffffffff 008f9300
|
||||
DS =0000 00000000 ffffffff 008f9300
|
||||
FS =0000 00000000 ffffffff 008f9300
|
||||
GS =ca00 000ca000 ffffffff 008f9300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00006962 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=000069a2 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=000f7d2d EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000005
|
||||
ESI=00000000 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=000f7d44 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000008 CCD=0000694e CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000005
|
||||
ESI=00000000 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=00007d47 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00000001 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=0000699c EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=00007d2a EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=0000695c CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=0000699c EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=000f7d2d EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000003
|
||||
ESI=06fd2080 EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=000f7d44 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000008 CCD=00006948 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000003
|
||||
ESI=06fd2080 EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=00007d47 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000004 CCD=00000001 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=000069a2 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=00007d2a EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00006962 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=000069a2 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=000f7d2d EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000005
|
||||
ESI=00000000 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=000f7d44 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000008 CCD=0000694e CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000005
|
||||
ESI=00000000 EDI=06ffee71 EBP=00006962 ESP=00006962
|
||||
EIP=00007d47 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=00000001 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=0000699c EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=00007d2a EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000000 CCD=0000695c CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=000f7d2d ECX=00001234 EDX=000069ff
|
||||
ESI=0000699c EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=000f7d2d EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000044 CCD=00000000 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
SMM: enter
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000003
|
||||
ESI=06f32080 EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=000f7d44 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
|
||||
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
|
||||
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
|
||||
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
|
||||
GDT= 000f6220 00000037
|
||||
IDT= 000f625e 00000000
|
||||
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000008 CCD=00006948 CCO=ADDL
|
||||
EFER=0000000000000000
|
||||
SMM: after RSM
|
||||
EAX=000000b5 EBX=00007d47 ECX=00005678 EDX=00000003
|
||||
ESI=06f32080 EDI=06ffee71 EBP=0000695c ESP=0000695c
|
||||
EIP=00007d47 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
|
||||
ES =da80 000da800 ffffffff 00809300
|
||||
CS =f000 000f0000 ffffffff 00809b00
|
||||
SS =0000 00000000 ffffffff 00809300
|
||||
DS =0000 00000000 ffffffff 00809300
|
||||
FS =0000 00000000 ffffffff 00809300
|
||||
GS =ca00 000ca000 ffffffff 00809300
|
||||
LDT=0000 00000000 0000ffff 00008200
|
||||
TR =0000 00000000 0000ffff 00008b00
|
||||
GDT= 00000000 00000000
|
||||
IDT= 00000000 000003ff
|
||||
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
|
||||
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
|
||||
DR6=00000000ffff0ff0 DR7=0000000000000400
|
||||
CCS=00000004 CCD=00000001 CCO=EFLAGS
|
||||
EFER=0000000000000000
|
||||
Servicing hardware INT=0x08
|
||||
BIN
Binary file not shown.
+318
@@ -0,0 +1,318 @@
|
||||
use crate::vga_buffer::{self, Color, ColorCode};
|
||||
|
||||
/// Hardcoded bank of 5-letter words embedded directly in the kernel binary.
|
||||
///
|
||||
/// These are common English words that work well for Wordle. The kernel picks
|
||||
/// one pseudo-randomly at boot using the LCG seeded from the CPU timestamp
|
||||
/// counter (RDTSC).
|
||||
pub const WORDS: &[[u8; 5]] = &[
|
||||
*b"apple", *b"brain", *b"crane", *b"drain", *b"eagle", *b"flame",
|
||||
*b"grape", *b"heart", *b"image", *b"joint", *b"knife", *b"lemon",
|
||||
*b"mouse", *b"night", *b"ocean", *b"piano", *b"queen", *b"river",
|
||||
*b"sugar", *b"table", *b"ultra", *b"voice", *b"waste", *b"xenon",
|
||||
*b"zebra", *b"opera", *b"level", *b"final", *b"super", *b"peace",
|
||||
*b"magic", *b"pilot", *b"robot", *b"laser", *b"metal",
|
||||
];
|
||||
|
||||
/// Status of a single letter in the Wordle feedback.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum LetterStatus {
|
||||
/// Letter in this position has not been evaluated yet (untyped or
|
||||
/// current guess in progress).
|
||||
Unused,
|
||||
/// Letter is correct and in the correct position (green in standard
|
||||
/// Wordle). The VGA background will be set to Green.
|
||||
Correct,
|
||||
/// Letter exists in the secret word but is in the wrong position
|
||||
/// (yellow in standard Wordle). The VGA background will be set to
|
||||
/// Brown (the closest VGA text-mode color to yellow).
|
||||
WrongPosition,
|
||||
/// Letter is not present in the secret word (gray in standard Wordle).
|
||||
/// The VGA background will be set to LightGray with black text.
|
||||
Incorrect,
|
||||
}
|
||||
|
||||
/// Top-level game state.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum GameState {
|
||||
Playing,
|
||||
Won,
|
||||
Lost,
|
||||
}
|
||||
|
||||
/// Complete Wordle game state machine.
|
||||
///
|
||||
/// Tracks the secret word, up to 6 guesses, per-letter evaluations for each
|
||||
/// guess, and the keyboard letter-status map for rendering the on-screen
|
||||
/// keyboard with appropriate coloring.
|
||||
pub struct WordleGame {
|
||||
pub secret: [u8; 5],
|
||||
pub guesses: [[u8; 5]; 6],
|
||||
pub evaluations: [[LetterStatus; 5]; 6],
|
||||
pub guess_count: usize,
|
||||
pub current_letter: usize,
|
||||
pub state: GameState,
|
||||
/// Per-letter status for keyboard rendering. Index 0 = 'A', 25 = 'Z'.
|
||||
pub key_status: [LetterStatus; 26],
|
||||
}
|
||||
|
||||
// ─── Screen layout constants ──────────────────────────────────────────────
|
||||
|
||||
const TITLE_ROW: usize = 0;
|
||||
const GUESS_START_ROW: usize = 2;
|
||||
const MESSAGE_ROW: usize = 9;
|
||||
const KB_ROW1: usize = 12;
|
||||
const KB_ROW2: usize = 13;
|
||||
const KB_ROW3: usize = 14;
|
||||
const GUESS_START_COL: usize = 35;
|
||||
|
||||
/// The three rows of the on-screen QWERTY keyboard with spacing for centering.
|
||||
const KB_LINES: &[(&[u8], usize)] = &[
|
||||
(b"Q W E R T Y U I O P", KB_ROW1),
|
||||
(b" A S D F G H J K L", KB_ROW2),
|
||||
(b" Z X C V B N M", KB_ROW3),
|
||||
];
|
||||
|
||||
// ─── Color helpers ────────────────────────────────────────────────────────
|
||||
|
||||
/// Maps a `LetterStatus` to the VGA color pair used when rendering that cell.
|
||||
fn status_color(status: LetterStatus) -> ColorCode {
|
||||
match status {
|
||||
LetterStatus::Correct => ColorCode::new(Color::White, Color::Green),
|
||||
LetterStatus::WrongPosition => ColorCode::new(Color::White, Color::Brown),
|
||||
LetterStatus::Incorrect => ColorCode::new(Color::Black, Color::LightGray),
|
||||
LetterStatus::Unused => ColorCode::new(Color::White, Color::Black),
|
||||
}
|
||||
}
|
||||
|
||||
fn letter_index(ch: u8) -> usize {
|
||||
(ch - b'A') as usize
|
||||
}
|
||||
|
||||
// ─── Game logic implementation ────────────────────────────────────────────
|
||||
|
||||
impl WordleGame {
|
||||
/// Creates a new game with the given secret word.
|
||||
pub fn new(secret: [u8; 5]) -> Self {
|
||||
WordleGame {
|
||||
secret,
|
||||
guesses: [[b' '; 5]; 6],
|
||||
evaluations: [[LetterStatus::Unused; 5]; 6],
|
||||
guess_count: 0,
|
||||
current_letter: 0,
|
||||
state: GameState::Playing,
|
||||
key_status: [LetterStatus::Unused; 26],
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a letter to the current guess, if space remains.
|
||||
pub fn add_letter(&mut self, letter: u8) {
|
||||
if self.current_letter < 5 {
|
||||
self.guesses[self.guess_count][self.current_letter] = letter;
|
||||
self.current_letter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes the most recently typed letter from the current guess.
|
||||
pub fn delete_letter(&mut self) {
|
||||
if self.current_letter > 0 {
|
||||
self.current_letter -= 1;
|
||||
self.guesses[self.guess_count][self.current_letter] = b' ';
|
||||
}
|
||||
}
|
||||
|
||||
/// Submits the current guess for evaluation.
|
||||
///
|
||||
/// Returns `None` if the guess is incomplete (< 5 letters).
|
||||
/// Returns `Some(true)` if the game ended (won or lost).
|
||||
/// Returns `Some(false)` if the guess was valid and the game continues.
|
||||
pub fn submit_guess(&mut self) -> Option<bool> {
|
||||
if self.current_letter < 5 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let guess = self.guesses[self.guess_count];
|
||||
let evaluation = evaluate_guess(&self.secret, &guess);
|
||||
self.evaluations[self.guess_count] = evaluation;
|
||||
|
||||
// Update the keyboard letter statuses. Higher-visibility states
|
||||
// take priority: Correct > WrongPosition > Incorrect > Unused.
|
||||
for i in 0..5 {
|
||||
let idx = letter_index(guess[i]);
|
||||
let new = evaluation[i];
|
||||
let current = self.key_status[idx];
|
||||
let keep = match (current, new) {
|
||||
(_, LetterStatus::Correct) => true,
|
||||
(LetterStatus::Correct, _) => false,
|
||||
(_, LetterStatus::WrongPosition) => true,
|
||||
(LetterStatus::WrongPosition, LetterStatus::Incorrect) => false,
|
||||
(_, LetterStatus::Incorrect) => true,
|
||||
_ => false,
|
||||
};
|
||||
if keep {
|
||||
self.key_status[idx] = new;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance to the next guess slot before checking result so that
|
||||
// render_guesses can display the evaluation of this guess (it uses
|
||||
// i < guess_count to decide which rows are confirmed).
|
||||
self.guess_count += 1;
|
||||
self.current_letter = 0;
|
||||
|
||||
if evaluation.iter().all(|&s| s == LetterStatus::Correct) {
|
||||
self.state = GameState::Won;
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
if self.guess_count >= 6 {
|
||||
self.state = GameState::Lost;
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
Some(false)
|
||||
}
|
||||
|
||||
// ─── Rendering ────────────────────────────────────────────────────────
|
||||
|
||||
/// Full-screen redraw: clears the display, then draws every element.
|
||||
pub fn render_all(&self) {
|
||||
vga_buffer::clear_screen(Color::Black);
|
||||
self.render_title();
|
||||
self.render_guesses();
|
||||
self.render_keyboard();
|
||||
self.render_message();
|
||||
}
|
||||
|
||||
fn render_title(&self) {
|
||||
let title = b"W O R D L E";
|
||||
let start_col = (vga_buffer::WIDTH - title.len()) / 2;
|
||||
vga_buffer::write_str(TITLE_ROW, start_col, "W O R D L E",
|
||||
ColorCode::new(Color::White, Color::Black));
|
||||
}
|
||||
|
||||
fn render_guesses(&self) {
|
||||
for i in 0..6 {
|
||||
let row = GUESS_START_ROW + i;
|
||||
|
||||
if i < self.guess_count {
|
||||
// Confirmed guess — show with evaluation colors.
|
||||
for j in 0..5 {
|
||||
let col = GUESS_START_COL + j * 2;
|
||||
let color = status_color(self.evaluations[i][j]);
|
||||
vga_buffer::write_char(row, col, self.guesses[i][j], color);
|
||||
}
|
||||
} else if i == self.guess_count && self.state == GameState::Playing {
|
||||
// Current guess being typed.
|
||||
for j in 0..5 {
|
||||
let col = GUESS_START_COL + j * 2;
|
||||
if j < self.current_letter {
|
||||
vga_buffer::write_char(row, col, self.guesses[i][j],
|
||||
ColorCode::new(Color::White, Color::Black));
|
||||
} else if j == self.current_letter {
|
||||
// Cursor indicator: an underscore.
|
||||
vga_buffer::write_char(row, col, b'_',
|
||||
ColorCode::new(Color::White, Color::Black));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Empty rows (future guesses) are left as cleared spaces.
|
||||
}
|
||||
}
|
||||
|
||||
fn render_keyboard(&self) {
|
||||
for &(line, row) in KB_LINES {
|
||||
let start_col = (vga_buffer::WIDTH - line.len()) / 2;
|
||||
for (i, &ch) in line.iter().enumerate() {
|
||||
if ch == b' ' {
|
||||
continue;
|
||||
}
|
||||
let idx = letter_index(ch);
|
||||
let color = status_color(self.key_status[idx]);
|
||||
vga_buffer::write_char(row, start_col + i, ch, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_message(&self) {
|
||||
match self.state {
|
||||
GameState::Won => {
|
||||
let msg = "Congratulations! Press any key to restart";
|
||||
let start_col = (vga_buffer::WIDTH - msg.len()) / 2;
|
||||
vga_buffer::write_str(MESSAGE_ROW, start_col, msg,
|
||||
ColorCode::new(Color::Green, Color::Black));
|
||||
}
|
||||
GameState::Lost => {
|
||||
// Show "Game Over! The word was: XXXXX"
|
||||
let prefix = "Game Over! The word was: ";
|
||||
let total_len = prefix.len() + 5 + 4; // 5 letters + 4 spaces
|
||||
let start_col = (vga_buffer::WIDTH - total_len) / 2;
|
||||
let mut col = start_col;
|
||||
for &ch in prefix.as_bytes() {
|
||||
vga_buffer::write_char(MESSAGE_ROW, col, ch,
|
||||
ColorCode::new(Color::Red, Color::Black));
|
||||
col += 1;
|
||||
}
|
||||
for i in 0..5 {
|
||||
col += 1; // space between letters
|
||||
let color = status_color(self.evaluations[5][i]);
|
||||
vga_buffer::write_char(MESSAGE_ROW, col, self.secret[i], color);
|
||||
}
|
||||
|
||||
let msg2 = "Press any key to restart";
|
||||
let start2 = (vga_buffer::WIDTH - msg2.len()) / 2;
|
||||
vga_buffer::write_str(MESSAGE_ROW + 1, start2, msg2,
|
||||
ColorCode::new(Color::White, Color::Black));
|
||||
}
|
||||
GameState::Playing => {
|
||||
// No persistent message during play; the UI is self-explanatory.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Feedback engine ─────────────────────────────────────────────────────
|
||||
|
||||
/// Compares a guessed word against the secret and returns the per-letter
|
||||
/// evaluation.
|
||||
///
|
||||
/// Algorithm (identical to the original Wordle):
|
||||
/// 1. First pass: mark exact positional matches as `Correct`.
|
||||
/// 2. Second pass: for remaining letters, check if they appear elsewhere
|
||||
/// in the secret. If so, mark as `WrongPosition`; otherwise `Incorrect`.
|
||||
///
|
||||
/// A letter in the secret can only match one guessed letter. Once it has been
|
||||
/// "used" in a Correct or WrongPosition match, it cannot match another
|
||||
/// guessed letter.
|
||||
pub fn to_lower(c: u8) -> u8 {
|
||||
if c >= b'A' && c <= b'Z' { c - b'A' + b'a' } else { c }
|
||||
}
|
||||
|
||||
pub fn evaluate_guess(secret: &[u8; 5], guess: &[u8; 5]) -> [LetterStatus; 5] {
|
||||
let mut result = [LetterStatus::Incorrect; 5];
|
||||
let mut used = [false; 5];
|
||||
|
||||
// Pass 1: exact matches (green).
|
||||
for i in 0..5 {
|
||||
if to_lower(guess[i]) == secret[i] {
|
||||
result[i] = LetterStatus::Correct;
|
||||
used[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: wrong-position matches (yellow).
|
||||
for i in 0..5 {
|
||||
if result[i] == LetterStatus::Correct {
|
||||
continue;
|
||||
}
|
||||
for j in 0..5 {
|
||||
if !used[j] && to_lower(guess[i]) == secret[j] {
|
||||
result[i] = LetterStatus::WrongPosition;
|
||||
used[j] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
/// Actions produced by the PS/2 keyboard decoder.
|
||||
///
|
||||
/// Only A–Z letters, Enter, and Backspace are relevant for the Wordle game.
|
||||
/// All other keys (modifiers, function keys, arrows) are silently ignored.
|
||||
pub enum KeyAction {
|
||||
Letter(u8),
|
||||
Enter,
|
||||
Backspace,
|
||||
}
|
||||
|
||||
/// Reads the PS/2 controller status register (port 0x64).
|
||||
///
|
||||
/// Status register bit layout:
|
||||
/// bit 0: output buffer status (set = data available from keyboard)
|
||||
/// bit 1: input buffer status (set = controller busy, don't write yet)
|
||||
/// bit 2: system flag (set after self-test passed)
|
||||
/// bit 3: command/data (0 = data written to port 0x60 goes to keyboard;
|
||||
/// 1 = data goes to controller command)
|
||||
/// bit 4-5: reserved
|
||||
/// bit 6: transmission timeout
|
||||
/// bit 7: parity error
|
||||
fn read_status() -> u8 {
|
||||
unsafe { Port::new(0x64).read() }
|
||||
}
|
||||
|
||||
/// Reads a byte from the PS/2 data port (port 0x60).
|
||||
///
|
||||
/// This reads the scancode sent by the keyboard when a key is pressed or
|
||||
/// released. Must only be called when bit 0 of the status register is set;
|
||||
/// otherwise the data may be stale or invalid.
|
||||
fn read_data() -> u8 {
|
||||
unsafe { Port::new(0x60).read() }
|
||||
}
|
||||
|
||||
/// Returns true when a byte is available from the keyboard.
|
||||
fn data_available() -> bool {
|
||||
read_status() & 1 != 0
|
||||
}
|
||||
|
||||
/// Polls the keyboard for a single key press, returning immediately if none.
|
||||
///
|
||||
/// This is called from the main game loop and is non-blocking. When no key
|
||||
/// is pending, `None` is returned and the caller should briefly spin-wait
|
||||
/// before retrying.
|
||||
///
|
||||
/// ## Scan code handling (Set 1)
|
||||
/// The PS/2 controller is typically in "translated" mode, converting native
|
||||
/// Set 2 scancodes to Set 1 on the fly. In Set 1:
|
||||
/// - Make codes (key pressed): 0x01 – 0x7F
|
||||
/// - Break codes (key released): 0x81 – 0xFF (= make_code | 0x80)
|
||||
/// - Extended keys (arrows, etc.): prefixed with 0xE0
|
||||
///
|
||||
/// We ignore break codes and extended codes since we only care about when
|
||||
/// a letter key is pressed.
|
||||
pub fn poll_key() -> Option<KeyAction> {
|
||||
if !data_available() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let scancode = read_data();
|
||||
|
||||
// Ignore the extended-key prefix (0xE0). The next byte is the actual
|
||||
// scancode for the extended key (e.g., arrow, home, etc.), which we
|
||||
// don't need — discard it too.
|
||||
if scancode == 0xE0 {
|
||||
while !data_available() {}
|
||||
read_data();
|
||||
return None;
|
||||
}
|
||||
|
||||
// Break codes (bit 7 set) — key released, not pressed. Ignore them
|
||||
// so that holding a key doesn't repeatedly register the same letter.
|
||||
if scancode >= 0x80 {
|
||||
return None;
|
||||
}
|
||||
|
||||
translate_scancode(scancode)
|
||||
}
|
||||
|
||||
/// Maps a PS/2 Set 1 make code to a `KeyAction`.
|
||||
///
|
||||
/// Scan code set 1 layout for the main alphanumeric block:
|
||||
///
|
||||
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
|
||||
/// │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │
|
||||
/// │0x10│0x11│0x12│0x13│0x14│0x15│0x16│0x17│0x18│0x19│
|
||||
/// ├────┼────┼────┼────┼────┼────┼────┼────┼────┼────┤
|
||||
/// │ A │ S │ D │ F │ G │ H │ J │ K │ L │ │
|
||||
/// │0x1E│0x1F│0x20│0x21│0x22│0x23│0x24│0x25│0x26│ │
|
||||
/// ├────┼────┼────┼────┼────┼────┼────┼────┼────┼────┤
|
||||
/// │ Z │ X │ C │ V │ B │ N │ M │ │ │ │
|
||||
/// │0x2C│0x2D│0x2E│0x2F│0x30│0x31│0x32│ │ │ │
|
||||
/// └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
|
||||
///
|
||||
/// Enter: 0x1C Backspace: 0x0E
|
||||
fn translate_scancode(scancode: u8) -> Option<KeyAction> {
|
||||
match scancode {
|
||||
0x0E => Some(KeyAction::Backspace),
|
||||
0x1C => Some(KeyAction::Enter),
|
||||
0x10 => Some(KeyAction::Letter(b'Q')),
|
||||
0x11 => Some(KeyAction::Letter(b'W')),
|
||||
0x12 => Some(KeyAction::Letter(b'E')),
|
||||
0x13 => Some(KeyAction::Letter(b'R')),
|
||||
0x14 => Some(KeyAction::Letter(b'T')),
|
||||
0x15 => Some(KeyAction::Letter(b'Y')),
|
||||
0x16 => Some(KeyAction::Letter(b'U')),
|
||||
0x17 => Some(KeyAction::Letter(b'I')),
|
||||
0x18 => Some(KeyAction::Letter(b'O')),
|
||||
0x19 => Some(KeyAction::Letter(b'P')),
|
||||
0x1E => Some(KeyAction::Letter(b'A')),
|
||||
0x1F => Some(KeyAction::Letter(b'S')),
|
||||
0x20 => Some(KeyAction::Letter(b'D')),
|
||||
0x21 => Some(KeyAction::Letter(b'F')),
|
||||
0x22 => Some(KeyAction::Letter(b'G')),
|
||||
0x23 => Some(KeyAction::Letter(b'H')),
|
||||
0x24 => Some(KeyAction::Letter(b'J')),
|
||||
0x25 => Some(KeyAction::Letter(b'K')),
|
||||
0x26 => Some(KeyAction::Letter(b'L')),
|
||||
0x2C => Some(KeyAction::Letter(b'Z')),
|
||||
0x2D => Some(KeyAction::Letter(b'X')),
|
||||
0x2E => Some(KeyAction::Letter(b'C')),
|
||||
0x2F => Some(KeyAction::Letter(b'V')),
|
||||
0x30 => Some(KeyAction::Letter(b'B')),
|
||||
0x31 => Some(KeyAction::Letter(b'N')),
|
||||
0x32 => Some(KeyAction::Letter(b'M')),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
ENTRY(_start);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x200000;
|
||||
|
||||
.rodata : ALIGN(4K)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.text : ALIGN(4K)
|
||||
{
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.data.rel.ro : ALIGN(4K)
|
||||
{
|
||||
*(.data.rel.ro .data.rel.ro.*)
|
||||
}
|
||||
|
||||
.data : ALIGN(4K)
|
||||
{
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
.got : ALIGN(4K)
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.bss : ALIGN(4K)
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
*(.debug_abbrev)
|
||||
*(.debug_info)
|
||||
*(.debug_aranges)
|
||||
*(.debug_ranges)
|
||||
*(.debug_str)
|
||||
*(.debug_frame)
|
||||
*(.debug_line)
|
||||
*(.debug_loc)
|
||||
*(.symtab)
|
||||
*(.strtab)
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod vga_buffer;
|
||||
mod keyboard;
|
||||
mod rng;
|
||||
mod game;
|
||||
|
||||
use game::{GameState, WordleGame, WORDS};
|
||||
use keyboard::KeyAction;
|
||||
use rng::Lcg;
|
||||
use vga_buffer::{Color, ColorCode};
|
||||
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
|
||||
entry_point!(kernel_main);
|
||||
|
||||
// Called by the bootloader after it has set up 64-bit long mode, page tables,
|
||||
// and a stack. The `boot_info` parameter provides information about the
|
||||
// memory map, framebuffer, etc. — but for our VGA-text-mode display we
|
||||
// don't need it.
|
||||
//
|
||||
// How the bootloader works:
|
||||
// 1. BIOS/UEFI loads the bootloader (from `bootloader` crate).
|
||||
// 2. Bootloader transitions CPU from real mode → protected mode → long mode,
|
||||
// sets up page tables with VGA framebuffer at 0xB8000 identity-mapped,
|
||||
// loads our ELF, and jumps to kernel_main.
|
||||
// 3. We arrive with interrupts disabled (RFLAGS.IF = 0), at CPL 0 (ring 0).
|
||||
|
||||
fn kernel_main(_boot_info: &'static BootInfo) -> ! {
|
||||
// ── Initialisation ─────────────────────────────────────────────────
|
||||
vga_buffer::clear_screen(Color::Black);
|
||||
|
||||
// ── Main game loop (runs forever, restarting after each game) ──────
|
||||
loop {
|
||||
// Seed the RNG from the CPU timestamp counter so every boot picks
|
||||
// a different secret word (assuming the machine has been on for a
|
||||
// different amount of time).
|
||||
let mut rng = Lcg::from_tsc();
|
||||
let secret = WORDS[rng.next_range(WORDS.len())];
|
||||
|
||||
let mut game = WordleGame::new(secret);
|
||||
game.render_all();
|
||||
|
||||
// ── Per-game input loop ────────────────────────────────────────
|
||||
loop {
|
||||
if let Some(action) = keyboard::poll_key() {
|
||||
match action {
|
||||
KeyAction::Letter(ch) => game.add_letter(ch),
|
||||
KeyAction::Backspace => game.delete_letter(),
|
||||
KeyAction::Enter => {
|
||||
if game.submit_guess().is_none() {
|
||||
// Incomplete guess — the game shows nothing
|
||||
// for this; we just re-render as-is.
|
||||
}
|
||||
}
|
||||
}
|
||||
game.render_all();
|
||||
|
||||
if game.state == GameState::Won || game.state == GameState::Lost {
|
||||
// Wait for any key press, then restart the game.
|
||||
wait_for_keypress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Brief spin delay to keep the CPU from saturating at 100 %
|
||||
// while polling. 10k iterations of `pause` is roughly 10–50 µs
|
||||
// on modern CPUs — invisible to human input but vastly reduces
|
||||
// power draw.
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Blocks until any key is pressed (used between games).
|
||||
fn wait_for_keypress() {
|
||||
loop {
|
||||
if keyboard::poll_key().is_some() {
|
||||
return;
|
||||
}
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
|
||||
/// Short delay using the x86 `pause` instruction (rep; nop).
|
||||
///
|
||||
/// The `pause` instruction hints to the CPU that this is a spin-wait loop,
|
||||
/// allowing it to reduce power consumption and improve hyper-thread
|
||||
/// performance. It behaves as a no-op architecturally.
|
||||
fn spin_delay() {
|
||||
for _ in 0..10000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Panic handler — invoked on unrecoverable errors.
|
||||
///
|
||||
/// Displays a red crash screen with a message, then halts forever.
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
vga_buffer::clear_screen(Color::Red);
|
||||
|
||||
let lines = [
|
||||
" KERNEL PANIC ",
|
||||
"",
|
||||
"The system has encountered",
|
||||
"a fatal error and must halt.",
|
||||
];
|
||||
for (i, &line) in lines.iter().enumerate() {
|
||||
let col = (vga_buffer::WIDTH - line.len()) / 2;
|
||||
vga_buffer::write_str(10 + i, col, line,
|
||||
ColorCode::new(Color::White, Color::Red));
|
||||
}
|
||||
|
||||
// The panic message payload is the `Arguments` type. We could format
|
||||
// it with a custom `core::fmt::Write` implementation, but since we're
|
||||
// already in a crash state, we keep it simple: just display the line
|
||||
// number if available.
|
||||
if let Some(loc) = info.location() {
|
||||
let file = loc.file();
|
||||
let line_num = loc.line();
|
||||
// Truncated display for the panic location.
|
||||
let file_start = if file.len() > 30 { &file[file.len() - 30..] } else { file };
|
||||
// Print at a fixed offset; we can't do dynamic formatting in no_std
|
||||
// without a formatter.
|
||||
let _ = (file_start, line_num);
|
||||
}
|
||||
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
use core::arch::x86_64::_rdtsc;
|
||||
|
||||
/// A simple Linear Congruential Generator (LCG) for pseudo-random numbers.
|
||||
///
|
||||
/// Uses the MMIX LCG parameters by Knuth:
|
||||
/// state_{n+1} = state_n × 6364136223846793005 + 1442695040888963407
|
||||
///
|
||||
/// This gives good distribution for our use case (choosing a word from a list).
|
||||
/// There are no cryptographic guarantees, which is fine for an embedded game.
|
||||
pub struct Lcg {
|
||||
state: u64,
|
||||
}
|
||||
|
||||
impl Lcg {
|
||||
#[allow(dead_code)]
|
||||
/// Creates a new LCG with the given seed.
|
||||
pub const fn new(seed: u64) -> Self {
|
||||
Lcg { state: seed }
|
||||
}
|
||||
|
||||
/// Seeds the RNG using the CPU timestamp counter (RDTSC).
|
||||
///
|
||||
/// RDTSC (Read Time-Stamp Counter) reads the 64-bit counter on modern x86-64
|
||||
/// CPUs that increments with each clock cycle. Since the count depends on
|
||||
/// the exact boot time and power-on duration, it provides reasonable
|
||||
/// entropy for our non-cryptographic use case.
|
||||
///
|
||||
/// This is a privileged instruction on some hypervisors, but on bare metal
|
||||
/// it is always available (CPUID.80000001H:EDX.TSC[bit 4] is set on all
|
||||
/// x86-64 CPUs).
|
||||
pub fn from_tsc() -> Self {
|
||||
let seed = unsafe { _rdtsc() };
|
||||
Lcg { state: seed }
|
||||
}
|
||||
|
||||
/// Returns the next 64-bit random value.
|
||||
pub fn next_u64(&mut self) -> u64 {
|
||||
self.state = self
|
||||
.state
|
||||
.wrapping_mul(6364136223846793005)
|
||||
.wrapping_add(1442695040888963407);
|
||||
self.state
|
||||
}
|
||||
|
||||
/// Returns a random index in the range [0, range).
|
||||
///
|
||||
/// Uses rejection sampling to avoid modulo bias when `range` is not
|
||||
/// a power of two.
|
||||
pub fn next_range(&mut self, range: usize) -> usize {
|
||||
(self.next_u64() % range as u64) as usize
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use core::ptr::write_volatile;
|
||||
|
||||
/// VGA text mode display dimensions.
|
||||
///
|
||||
/// The standard VGA text mode provides an 80×25 grid of character cells.
|
||||
/// Each cell is 2 bytes: [ASCII byte] [attribute byte].
|
||||
/// The buffer starts at physical address 0xB8000 and is memory-mapped into
|
||||
/// the CPU's address space. The x86_64 bootloader identity-maps this region,
|
||||
/// so we can write to it with regular memory stores — but we must use volatile
|
||||
/// writes to prevent the compiler from optimizing away MMIO operations.
|
||||
pub const VGA_ADDR: *mut u8 = 0xB8000 as *mut u8;
|
||||
pub const WIDTH: usize = 80;
|
||||
pub const HEIGHT: usize = 25;
|
||||
|
||||
/// Standard VGA text-mode colors.
|
||||
///
|
||||
/// The attribute byte layout:
|
||||
/// bits 0-3: foreground color (0 = black, 15 = white)
|
||||
/// bits 4-6: background color (0-7, hardware limit; bit 7 = blink)
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Color {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Magenta = 5,
|
||||
Brown = 6,
|
||||
LightGray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
Pink = 13,
|
||||
Yellow = 14,
|
||||
White = 15,
|
||||
}
|
||||
|
||||
/// A packed attribute byte encoding foreground + background color.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ColorCode(u8);
|
||||
|
||||
impl ColorCode {
|
||||
/// Constructs a color code from foreground and background colors.
|
||||
///
|
||||
/// ## Hardware note
|
||||
/// The VGA attribute byte stores the background color in bits 4-6 (3 bits,
|
||||
/// limiting backgrounds to 0-7). Bit 7 is the blink enable bit, which we
|
||||
/// keep cleared. The foreground color uses bits 0-3 (including intensity
|
||||
/// on bit 3), giving 16 possible foreground colors.
|
||||
pub const fn new(fg: Color, bg: Color) -> ColorCode {
|
||||
ColorCode(((bg as u8) << 4) | (fg as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the entire VGA screen to the given background color.
|
||||
///
|
||||
/// Writes a space character (0x20) with the appropriate attribute byte
|
||||
/// to every cell on the screen.
|
||||
pub fn clear_screen(bg: Color) {
|
||||
let color = ColorCode::new(Color::White, bg);
|
||||
for offset in (0..(WIDTH * HEIGHT * 2)).step_by(2) {
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), b' ');
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a single character at position (row, col) with the given color.
|
||||
///
|
||||
/// The position is bounds-checked against the 80×25 screen. Writes outside
|
||||
/// the visible area are silently ignored.
|
||||
pub fn write_char(row: usize, col: usize, ch: u8, color: ColorCode) {
|
||||
if row < HEIGHT && col < WIDTH {
|
||||
let offset = (row * WIDTH + col) * 2;
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), ch);
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a string starting at position (row, col) with the given color.
|
||||
///
|
||||
/// Stops at the right edge of the screen to avoid wrapping.
|
||||
pub fn write_str(row: usize, col: usize, s: &str, color: ColorCode) {
|
||||
for (i, &ch) in s.as_bytes().iter().enumerate() {
|
||||
if col + i < WIDTH {
|
||||
write_char(row, col + i, ch, color);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
W O R D L E _ Q W E R T Y U I O P A S D F G H J K L Z X C V B N M Ao Pp Pp Lp Eo guess=APPLE secret= O C E A N
|
||||
@@ -0,0 +1 @@
|
||||
W O R D L E Cp Rp Ao Np E/ A/ P/ P/ L/ E/ Congratulations! Press any key to restart Q W E/ Rp T Y U I O P/ A/ S D F G H J K L/ Z X Cp V B Np M A/ P/ P/ L/ E/ guess=APPLE secret= A P P L E Secret: A P P L E
|
||||
Reference in New Issue
Block a user