Star forth v4.0.0 #3
+67
-2
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-10-05T19:24:40Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-10-05T20:03:22Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
@@ -30,6 +30,7 @@
|
||||
| `turtle.4th` | 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108 | `0x4d470418ca543365` | n/a |
|
||||
| `user-font-demo.4th` | 4200, 4201, 4202 | `0xce1fd7d1b581a56d` | n/a |
|
||||
| `v4:forth79.4th` | 6000 | `0xa4b74bdc7deaf204` | n/a |
|
||||
| `v4:post79.4th` | 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063 | `0x24df7b11992128ed` | n/a |
|
||||
| `workload-0.4th` | 2200, 2201 | `0x93f86f60aeba8feb` | n/a |
|
||||
| `workload-1-lite.4th` | 5058, 5059 | `0x44a7a7e3176dcc8d` | n/a |
|
||||
| `workload-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | n/a |
|
||||
@@ -368,10 +369,74 @@
|
||||
| 5114 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
|
||||
| 5115 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
|
||||
| 6000 | `v4:forth79.4th` | `0xa4b74bdc7deaf204` | ok |
|
||||
| 7000 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7001 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7002 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7003 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7004 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7005 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7006 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7007 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7008 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7009 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7010 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7011 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7012 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7013 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7014 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7015 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7016 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7017 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7018 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7019 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7020 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7021 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7022 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7023 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7024 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7025 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7026 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7027 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7028 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7029 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7030 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7031 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7032 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7033 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7034 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7035 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7036 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7037 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7038 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7039 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7040 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7041 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7042 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7043 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7044 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7045 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7046 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7047 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7048 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7049 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7050 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7051 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7052 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7053 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7054 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7055 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7056 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7057 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7058 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7059 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7060 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7061 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7062 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
| 7063 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
|
||||
|
||||
## Conflicts
|
||||
|
||||
None.
|
||||
|
||||
---
|
||||
*37 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
||||
*38 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;042;160t[2J[001;001H[2J[001;001H[8;056;240t[2J[001;001HBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
RAW SERIAL UP
|
||||
[CKPT 002] Serial (COM1) initialized
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
EBS...
|
||||
EBS OK
|
||||
Calling kernel_main (monolithic)...
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: amd64
|
||||
Build: Oct 5 2026 16:01:18
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 131
|
||||
Total memory: 1023 MB
|
||||
Usable memory: 968 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 249248
|
||||
Free pages : 247725
|
||||
Used pages : 1523
|
||||
Total MB : 973
|
||||
Free MB : 967
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
APIC: IA32_APIC_BASE MSR=0x00000000fee00900
|
||||
APIC: stale-ISR drain: 0 EOI(s) issued
|
||||
APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear)
|
||||
APIC: init done
|
||||
|
||||
I/O APIC: init...
|
||||
I/O APIC: base=0xfec00000, gsi_base=0, overrides=5
|
||||
override: source=00 gsi=2 flags=0x0000
|
||||
override: source=05 gsi=5 flags=0x000d
|
||||
override: source=09 gsi=9 flags=0x000d
|
||||
override: source=0a gsi=10 flags=0x000d
|
||||
override: source=0b gsi=11 flags=0x000d
|
||||
i8042: keyboard ACKed enable-scanning
|
||||
i8042: IRQ1 enabled in controller config byte
|
||||
I/O APIC: keyboard IRQ1 routed (masked)
|
||||
|
||||
Timer: init...
|
||||
Timer: init start
|
||||
Timer: PM_TMR_BLK discovered from FADT at port 1544
|
||||
Timer: VM mode detected (hypervisor present).
|
||||
Timer: HPET calibration disabled (VM-exit MMIO would poison timing).
|
||||
Timer: WARNING: invariant TSC not present under hypervisor.
|
||||
Timer: continuing in RELATIVE mode (no determinism guarantees).
|
||||
Timer: RDTSCP not present; using RDTSC (less serialized).
|
||||
Timer: CPUID frequency unavailable; trying PM Timer...
|
||||
Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2102894063 Hz
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 24641536
|
||||
Heap end addr: 561512448
|
||||
|
||||
Heartbeat: init...
|
||||
APIC Timer: calibrating...
|
||||
APIC Timer: apic_hz=1010732930, tick_hz=100, initial_count=10107329
|
||||
APIC Timer: configured (masked, ready to start)
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
|
||||
PARITY:OK
|
||||
ok>
|
||||
@@ -0,0 +1,82 @@
|
||||
UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026)
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;031;100t[2J[001;001HBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found
|
||||
BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found
|
||||
BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Collecting boot information...
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: aarch64
|
||||
Build: Oct 5 2026 16:02:10
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 108
|
||||
Total memory: 4093 MB
|
||||
Usable memory: 4056 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 1039860
|
||||
Free pages : 1038449
|
||||
Used pages : 1411
|
||||
Total MB : 4061
|
||||
Free MB : 4056
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
AArch64: running at EL1
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PSCI: no DTB -- using HVC (QEMU virt-machine default)
|
||||
GICv2: no DTB GIC node -- using QEMU virt-machine defaults
|
||||
GICv2: distributor+CPU interface enabled, PPI 30
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: AArch64 generic timer initialised.
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 2147483608
|
||||
Free bytes: 2147483608
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 1207959552
|
||||
Heap end addr: 3355443200
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
|
||||
PARITY:OK
|
||||
ok>
|
||||
@@ -0,0 +1,152 @@
|
||||
|
||||
OpenSBI v1.8
|
||||
____ _____ ____ _____
|
||||
/ __ \ / ____| _ \_ _|
|
||||
| | | |_ __ ___ _ __ | (___ | |_) || |
|
||||
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
|
||||
| |__| | |_) | __/ | | |____) | |_) || |_
|
||||
\____/| .__/ \___|_| |_|_____/|____/_____|
|
||||
| |
|
||||
|_|
|
||||
|
||||
Platform Name : riscv-virtio,qemu
|
||||
Platform Features : medeleg
|
||||
Platform HART Count : 1
|
||||
Platform HART Protection : pmp
|
||||
Platform IPI Device : aclint-mswi
|
||||
Platform Timer Device : aclint-mtimer @ 10000000Hz
|
||||
Platform Console Device : uart8250
|
||||
Platform HSM Device : ---
|
||||
Platform PMU Device : ---
|
||||
Platform Reboot Device : syscon-reboot
|
||||
Platform Shutdown Device : syscon-poweroff
|
||||
Platform Suspend Device : ---
|
||||
Platform CPPC Device : ---
|
||||
Firmware Base : 0x80000000
|
||||
Firmware Size : 321 KB
|
||||
Firmware RW Offset : 0x40000
|
||||
Firmware RW Size : 65 KB
|
||||
Firmware Heap Offset : 0x47000
|
||||
Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free)
|
||||
Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free)
|
||||
Runtime SBI Version : 3.0
|
||||
Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr
|
||||
Experimental SBI Extensions : none
|
||||
|
||||
Domain0 Name : root
|
||||
Domain0 Boot HART : 0
|
||||
Domain0 HARTs : 0*
|
||||
Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: ()
|
||||
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: ()
|
||||
Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
|
||||
Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
|
||||
Domain0 Next Address : 0x0000000020000000
|
||||
Domain0 Next Arg1 : 0x00000000bfe00000
|
||||
Domain0 Next Mode : S-mode
|
||||
Domain0 SysReset : yes
|
||||
Domain0 SysSuspend : yes
|
||||
|
||||
Boot HART ID : 0
|
||||
Boot HART Domain : root
|
||||
Boot HART Priv Version : v1.12
|
||||
Boot HART Base ISA : rv64imafdch
|
||||
Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
|
||||
Boot HART PMP Count : 16
|
||||
Boot HART PMP Granularity : 2 bits
|
||||
Boot HART PMP Address Bits : 54
|
||||
Boot HART MHPM Info : 16 (0x0007fff8)
|
||||
Boot HART Debug Triggers : 2 triggers
|
||||
Boot HART MIDELEG : 0x0000000000001666
|
||||
Boot HART MEDELEG : 0x0000000000f4b509
|
||||
[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-V EDK2 firmware version 2025.11-3ubuntu7.3
|
||||
Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850
|
||||
BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr
|
||||
om PciRoot(0x0)/Pci(0x1,0x0): Not Found
|
||||
[2J[001;001H[=3h[2J[009DStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
Calling kernel_main (monolithic)...
|
||||
riscv64 item 4.3.5a: satp state at kernel entry (before switch)
|
||||
satp.MODE = 0x000000000000000a
|
||||
satp.PPN = 0x00000000000bf868
|
||||
__kernel_start = 0x00000000bde99936
|
||||
riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: riscv64
|
||||
Build: Oct 5 2026 16:03:23
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 100
|
||||
Total memory: 1020 MB
|
||||
Usable memory: 977 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 250775
|
||||
Free pages : 250123
|
||||
Used pages : 652
|
||||
Total MB : 979
|
||||
Free MB : 977
|
||||
Used MB : 2
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000)
|
||||
PLIC: init (S-mode context 1, threshold=0)
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree)
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 2214588416
|
||||
Heap end addr: 2751459328
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
|
||||
PARITY:OK
|
||||
ok>
|
||||
+14
@@ -129,6 +129,20 @@ $(BINDIR)/boot-$(1).txt: $(BINDIR)/starforth4-$(1)
|
||||
endef
|
||||
$(foreach i,$(HOSTED_ISAS),$(eval $(call HOSTED_RULE,$(i))))
|
||||
|
||||
# `make post` builds the amd64 system with POST in its boot
|
||||
# (V4_POST_AT_BOOT=1, system/boot.c) and boots it: the POST capsule,
|
||||
# ../capsules/v4/post79.4th, is loaded after forth79.4th and must end with a
|
||||
# clean tally. `make post79` writes that capsule again from v3's cases
|
||||
# (tools/mkpost.py); it needs the hosted v3 binary.
|
||||
.PHONY: post post79
|
||||
$(BINDIR)/starforth4-post: $(HERE)/tools/hosted.c $(BINDIR)/v4_image_64.c $(CAPSULE_DIR_C) $(ENGINE_SRCS) $(SYSTEM_SRCS) $(wildcard $(HERE)/include/v4/*.h) $(HERE)/Makefile
|
||||
$(CC_amd64) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -I$(HERE)/include -DV4_CELL_BITS=64 $(HOST_DEFS) -c $(HERE)/tools/hosted.c -o $(BINDIR)/hosted-post.o
|
||||
$(CC_amd64) $(SYSTEM_CFLAGS) -DV4_POST_AT_BOOT=1 -static $(BINDIR)/hosted-post.o $(BINDIR)/v4_image_64.c $(CAPSULE_DIR_C) $(ENGINE_SRCS) $(SYSTEM_SRCS) -o $@
|
||||
post: $(BINDIR)/starforth4-post
|
||||
@$(BINDIR)/starforth4-post < /dev/null
|
||||
post79:
|
||||
python3 $(HERE)/tools/mkpost.py
|
||||
|
||||
# `make hosted` builds the three. `make hosted-check` boots each with no
|
||||
# input and requires that all three print the same lines, ending in
|
||||
# PARITY:OK and the prompt: the same hashes on every ISA.
|
||||
|
||||
+46
-9
@@ -55,21 +55,58 @@ and fails unless their output is identical and ends in `PARITY:OK`.
|
||||
A capsule line the node does not answer ` ok` to ends the boot, naming the
|
||||
capsule, block and line, with `PARITY:FAIL` and `POST: FAILED`.
|
||||
|
||||
State, 2026-10-05: capsule loading works on all six builds. The three hosted
|
||||
binaries and the three bare-metal kernels (`clean qemu` with `STARFORTH_V4=1`)
|
||||
print the same four lines and reach `ok>`:
|
||||
State, 2026-10-05, after the POST work began: all six builds load
|
||||
`v4:forth79.4th` and reach `ok>` with the same lines:
|
||||
|
||||
```
|
||||
PARITY:V4_NUCLEUS words=292 image_hash=0x60b74e4f87adb0ac
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x0baed67626b4fac4
|
||||
PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
|
||||
PARITY:OK
|
||||
ok>
|
||||
```
|
||||
|
||||
Bare-metal logs: `logs/20261005-152955/amd64/`, `logs/20261005-154021/aarch64/`,
|
||||
`logs/20261005-154150/riscv64/`. Each run was ended once the prompt was in the
|
||||
Bare-metal logs: `logs/20261005-160144/amd64/`, `logs/20261005-160234/aarch64/`,
|
||||
`logs/20261005-160400/riscv64/`. Each run was ended once the prompt was in the
|
||||
log; nothing was typed at a bare-metal prompt, so keyboard input there is not
|
||||
yet verified. The capsules were unsigned (no signing key on this machine).
|
||||
|
||||
`forth79.4th` holds no definitions yet: all 292 words are still in the
|
||||
nucleus. There is no POST yet.
|
||||
`forth79.4th` holds no definitions yet: every word is still in the nucleus.
|
||||
|
||||
## POST
|
||||
|
||||
`capsules/v4/post79.4th` is v3's POST cases for the FORTH-79 Required Word
|
||||
Set, written by `v4/tools/mkpost.py` (`make -C v4 post79`): 537 cases in
|
||||
blocks 7000–7112, covering 111 of the 130 required words. Each case carries
|
||||
what the hosted v3 binary did with the same line — error or not, the stack,
|
||||
the length and checksum of what was printed — and v4 must do the same.
|
||||
|
||||
**POST does not pass yet, so it is not in the boot.** `make -C v4 post` builds
|
||||
the amd64 system with it (`-DV4_POST_AT_BOOT=1`) and boots it:
|
||||
|
||||
```
|
||||
PARITY:V4_POST tests=537 pass=439 fail=98
|
||||
PARITY:FAIL
|
||||
POST: FAILED
|
||||
```
|
||||
|
||||
The 98 are not yet sorted into v4 defects and differences that need a
|
||||
ruling. A first reading finds four kinds:
|
||||
|
||||
| Kind | About | Examples |
|
||||
|---|---|---|
|
||||
| The case prints or leaves a memory address, which differs between the two machines | 40 | `HERE`, `PAD`, `1 BLOCK`, `BL WORD`, `CONTEXT @ .`, `FIND` |
|
||||
| v3 departs from FORTH-79 and v4 follows the standard | 35 | `PICK` and `ROLL` count from 1; `<# # #S #>` take a double number; `LEAVE` ends the loop at the next `LOOP`; `>R` `R>` only inside a definition |
|
||||
| The case assumes v3's byte address units, where a v4 address unit is a cell (D-1) | 8 | `42 , HERE 8 - @`, `PAD 42 OVER !` |
|
||||
| Not yet understood | 15 | vocabulary cases, `LIST`'s layout, `16 BASE ! 255 .`, `321 EMIT`, cases v3 ends in an error and v4 does not |
|
||||
|
||||
Required words with no v3 case, and so no POST case: `U*` `U/MOD` `?`
|
||||
`EXECUTE` `KEY` `EXPECT` `QUERY` `U.` `CONVERT` `'` `."` `LITERAL` `STATE`
|
||||
`COMPILE` `[COMPILE]` `(` `QUIT` `BLK` `79-STANDARD`. `U*` and `U/MOD` are
|
||||
in neither v3 nor v4.
|
||||
|
||||
Twelve v3 cases are left out: three read the keyboard, two forget a word of
|
||||
the system, two store to the search order, and five leave v3 unable to
|
||||
continue in one session (`mkpost.py` prints the list).
|
||||
|
||||
The boot passes POST only on seeing the tally line with `fail=0`
|
||||
(`v4/system/boot.c`); that no line was refused is not enough.
|
||||
|
||||
@@ -68,6 +68,11 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
|
||||
\ FORTH-79: clear the return stack, set execution mode, return control to
|
||||
\ the terminal; no message is given. The data stack is left as it is.
|
||||
\ NODE-ERROR, by name: how a definition written in FORTH raises an error.
|
||||
\ A store of a code that is not zero is the trap of D-18 -- the word goes no
|
||||
\ further, the message for the code is printed (-1: the word has printed
|
||||
\ its own) and the line ends with ERROR. The codes are listed in core.v4.
|
||||
header NODE-ERROR inline : NODE-ERROR' NODE-ERROR ;
|
||||
header (CATCH) inline : (CATCH)' (CATCH) ;
|
||||
header (EMIT-HOOK) inline : (EMIT-HOOK)' (EMIT-HOOK) ;
|
||||
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
* the text goes. So the two start the same way and print the same lines:
|
||||
*
|
||||
* PARITY:V4_NUCLEUS words=N image_hash=0x...
|
||||
* PARITY:V4_CAPSULE name=... capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:V4_POST tests=N pass=N fail=N (printed by the POST capsule)
|
||||
* PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:OK
|
||||
* POST: PASSED
|
||||
* ok>
|
||||
*
|
||||
* or, if anything is wrong, what was wrong and then
|
||||
|
||||
+59
-2
@@ -11,7 +11,18 @@
|
||||
#include "starkernel/capsule_blocks.h"
|
||||
|
||||
/* The capsules, in the order they are loaded. */
|
||||
static const char *const boot_capsules[] = { "v4:forth79.4th" };
|
||||
/* POST is not yet part of the boot: v4:post79.4th does not pass yet
|
||||
* (v4/README.md). Build with -DV4_POST_AT_BOOT=1 to load it and to require
|
||||
* its clean tally; `make -C v4 post` does. */
|
||||
#ifndef V4_POST_AT_BOOT
|
||||
#define V4_POST_AT_BOOT 0
|
||||
#endif
|
||||
static const char *const boot_capsules[] = {
|
||||
"v4:forth79.4th",
|
||||
#if V4_POST_AT_BOOT
|
||||
"v4:post79.4th",
|
||||
#endif
|
||||
};
|
||||
|
||||
#define LINE_MAX 80u /* QUERY takes 80 characters, the new-line among them */
|
||||
#define STEP_LIMIT 4000000000ULL /* instruction words one line may take */
|
||||
@@ -105,6 +116,37 @@ typedef struct {
|
||||
unsigned len;
|
||||
} tail;
|
||||
|
||||
/* POST's verdict. The POST capsule ends by printing one line,
|
||||
* PARITY:V4_POST tests=N pass=N fail=N
|
||||
* and the boot passes only if it has seen that line with fail=0. That no
|
||||
* line was refused is not enough: a POST that was broken half way would
|
||||
* refuse nothing. */
|
||||
static char post_line[96];
|
||||
static unsigned post_len;
|
||||
static int post_seen, post_clean;
|
||||
|
||||
static int text_at(const char *line, unsigned len, unsigned at, const char *want)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; want[i]; i++)
|
||||
if (at + i >= len || line[at + i] != want[i]) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void post_watch(char c)
|
||||
{
|
||||
static const char clean[] = " fail=0";
|
||||
if (c != '\n') {
|
||||
if (post_len < sizeof post_line) post_line[post_len++] = c;
|
||||
return;
|
||||
}
|
||||
if (text_at(post_line, post_len, 0, "PARITY:V4_POST ")) {
|
||||
post_seen = 1;
|
||||
post_clean = post_len >= sizeof clean - 1 && text_at(post_line, post_len, post_len - (unsigned)(sizeof clean - 1), clean);
|
||||
}
|
||||
post_len = 0;
|
||||
}
|
||||
|
||||
static void tail_put(const v4_boot *b, tail *t, int show, char c)
|
||||
{
|
||||
unsigned i;
|
||||
@@ -130,7 +172,10 @@ static int run_to_prompt(const v4_boot *b, int show)
|
||||
for (;;) {
|
||||
(void)v4_exec_step_word(n, b->es, b->h);
|
||||
if (n->console_len) {
|
||||
for (i = 0; i < n->console_len; i++) tail_put(b, &t, show, (char)n->console[i]);
|
||||
for (i = 0; i < n->console_len; i++) {
|
||||
post_watch((char)n->console[i]);
|
||||
tail_put(b, &t, show, (char)n->console[i]);
|
||||
}
|
||||
n->console_len = 0;
|
||||
}
|
||||
if (n->stopped) { say(b, "\nV4: the node stopped on a fault\n"); return 0; }
|
||||
@@ -233,6 +278,7 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
post_len = 0; post_seen = 0; post_clean = 0;
|
||||
if (!v4_image_boot(b->n, b->es, b->h, b->im, disk, blocks)) {
|
||||
say(b, "V4: the nucleus image is not for this build of the engine\nPARITY:FAIL\nPOST: FAILED\n");
|
||||
return 0;
|
||||
@@ -247,7 +293,18 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
|
||||
|
||||
for (i = 0; i < sizeof boot_capsules / sizeof boot_capsules[0]; i++)
|
||||
if (!load_capsule(b, boot_capsules[i])) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
|
||||
#if V4_POST_AT_BOOT
|
||||
if (!post_seen || !post_clean) {
|
||||
say(b, post_seen ? "V4: POST reported failures\n" : "V4: POST did not report\n");
|
||||
say(b, "PARITY:FAIL\nPOST: FAILED\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if V4_POST_AT_BOOT
|
||||
say(b, "PARITY:OK\nPOST: PASSED\nok> ");
|
||||
#else
|
||||
say(b, "PARITY:OK\nok> ");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
Executable
+455
@@ -0,0 +1,455 @@
|
||||
#!/usr/bin/env python3
|
||||
"""mkpost.py -- write capsules/v4/post79.4th from v3's POST cases.
|
||||
|
||||
v4/tools/mkpost.py [--v3 PATH] [--report FILE]
|
||||
|
||||
A development tool, run when the cases change; its output is committed and
|
||||
reviewed like any source. docs/v4.0.0/NUCLEUS.md section 6.
|
||||
|
||||
What it does:
|
||||
|
||||
1. Reads v3's case tables, v3/src/test_runner/modules/*.c, in the order
|
||||
v3's own POST runs them. A case is a word, a name, a line of FORTH and
|
||||
whether an error is expected.
|
||||
2. Keeps the cases for words of the FORTH-79 Required Word Set.
|
||||
3. Runs every kept case, in order, in one session of the hosted v3 binary,
|
||||
and records what v3 did: an error or not, the data stack, and what was
|
||||
printed. v3 is the reference.
|
||||
4. Writes the harness and one case after another as a .4th capsule:
|
||||
|
||||
T{ DUP.basic name the case, start clean
|
||||
T| 5 DUP . . a line of the case, its output captured
|
||||
-> 5 5 }T 0 0 T= v3's stack; v3's output: length, checksum
|
||||
|
||||
or, for a case v3 ended with an error, ->ERR in place of the last
|
||||
line.
|
||||
|
||||
A case is left out, and listed in the report, when: its word reads the
|
||||
keyboard; it forgets a word of the system or damages it on purpose; v3 could
|
||||
not finish it in one
|
||||
session; or one of its lines cannot be cut to fit a 64-character block
|
||||
line.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_DIR = os.path.join(ROOT, "v3", "src", "test_runner", "modules")
|
||||
OUTPUT = os.path.join(ROOT, "capsules", "v4", "post79.4th")
|
||||
FIRST_BLOCK = 7000
|
||||
LINE_MAX = 64
|
||||
|
||||
# v3's POST order (v3/src/test_runner/test_runner.c, test_modules[]), the
|
||||
# modules that test FORTH-79 words.
|
||||
MODULES = [
|
||||
"stack_words_test.c", "return_stack_words_test.c", "memory_words_test.c",
|
||||
"arithmetic_words_test.c", "logical_words_test.c",
|
||||
"mixed_arithmetic_words_test.c", "double_words_test.c",
|
||||
"format_words_test.c", "string_words_test.c", "io_words_test.c",
|
||||
"block_words_test.c", "dictionary_words_test.c",
|
||||
"dictionary_manipulation_words_test.c", "vocabulary_words_test.c",
|
||||
"system_words_test.c", "defining_words_tests.c", "control_words_test.c",
|
||||
]
|
||||
|
||||
# The FORTH-79 Standard's Required Word Set, by the standard's own groups.
|
||||
# Written from the standard's word list; check it against the document
|
||||
# before relying on it for a claim of compliance.
|
||||
REQUIRED = """
|
||||
DUP DROP SWAP OVER ROT PICK ROLL ?DUP DEPTH >R R> R@
|
||||
< = > 0< 0= 0> D< U< NOT
|
||||
+ - * / MOD /MOD */ */MOD 1+ 1- 2+ 2- MAX MIN ABS NEGATE D+ DNEGATE
|
||||
U* U/MOD AND OR XOR
|
||||
@ ! C@ C! ? +! MOVE CMOVE FILL
|
||||
DO LOOP +LOOP I J LEAVE IF ELSE THEN BEGIN UNTIL WHILE REPEAT EXIT EXECUTE
|
||||
CR EMIT SPACE SPACES TYPE COUNT -TRAILING KEY EXPECT QUERY WORD
|
||||
BASE DECIMAL . U. CONVERT <# # #S HOLD SIGN #>
|
||||
LIST LOAD SCR BLOCK UPDATE BUFFER SAVE-BUFFERS EMPTY-BUFFERS
|
||||
: ; VARIABLE CONSTANT VOCABULARY CREATE DOES>
|
||||
CONTEXT CURRENT FORTH DEFINITIONS ' FIND FORGET
|
||||
, ALLOT ." IMMEDIATE LITERAL STATE [ ] COMPILE [COMPILE]
|
||||
( >IN ABORT QUIT HERE PAD BLK 79-STANDARD
|
||||
""".split()
|
||||
|
||||
# Words whose cases wait for the keyboard, which a boot cannot type at.
|
||||
KEYBOARD = {"KEY", "EXPECT", "QUERY"}
|
||||
|
||||
# ---- the harness: blocks FIRST_BLOCK up, FORTH-79 and the two nucleus hooks ----
|
||||
HARNESS = r"""
|
||||
( post79.4th -- POST for the FORTH-79 Required Word Set on v4. )
|
||||
( Generated by v4/tools/mkpost.py from v3's POST cases: do not )
|
||||
( edit. docs/v4.0.0/NUCLEUS.md section 6. )
|
||||
VARIABLE T# VARIABLE TPASS VARIABLE TFAIL VARIABLE TOPEN
|
||||
VARIABLE TBAD VARIABLE TWANT VARIABLE TLEN VARIABLE TSUM
|
||||
VARIABLE TDEP VARIABLE TBASE
|
||||
CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT
|
||||
0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! 10 TBASE !
|
||||
: TB ( -- baddr ) TBUF 4 * ;
|
||||
: TN ( -- baddr ) TNAME 4 * ;
|
||||
( T-EMIT is given every character a case prints: the first 255 )
|
||||
( are kept, all are counted and summed. )
|
||||
: T-EMIT ( c -- )
|
||||
DUP TSUM @ 31 * + 16777215 AND TSUM !
|
||||
TLEN @ 255 < IF TB TLEN @ + C! ELSE DROP THEN 1 TLEN +! ;
|
||||
=====
|
||||
: T-CLEAR ( i*x -- ) BEGIN DEPTH WHILE DROP REPEAT ;
|
||||
: T. ( n -- ) 0 <# #S #> TYPE ;
|
||||
( what a failing case printed, and the stack it left )
|
||||
: T-SHOW ( -- )
|
||||
." out<" TB TLEN @ 255 MIN TYPE ." > stack<"
|
||||
TDEP @ BEGIN DUP WHILE 1- DUP TSTK + @ . REPEAT DROP ." >" ;
|
||||
( the verdict on the case that is open, if one is )
|
||||
: T-CLOSE ( -- )
|
||||
TOPEN @ IF
|
||||
(CATCH) @ -1 = TWANT @ = 0= IF 1 TBAD ! THEN
|
||||
TBAD @ IF 1 TFAIL +!
|
||||
." POST FAIL: " TN COUNT TYPE T-SHOW CR
|
||||
ELSE 1 TPASS +! THEN
|
||||
0 TOPEN ! 0 (CATCH) ! TBASE @ BASE !
|
||||
THEN ;
|
||||
=====
|
||||
( T{ name begin a case: clean stack, errors caught )
|
||||
: T{ ( i*x -- ) T-CLOSE T-CLEAR
|
||||
BL WORD COUNT 31 MIN DUP TN C! TN 1+ SWAP CMOVE
|
||||
1 T# +! 1 TOPEN ! 0 TBAD ! 0 TWANT ! 0 TLEN ! 0 TSUM !
|
||||
0 TDEP ! 1 (CATCH) ! ;
|
||||
( T| ... a line of the case, what it prints captured )
|
||||
: T| ' T-EMIT (EMIT-HOOK) ! ; IMMEDIATE
|
||||
: T-END ( -- ) 0 (EMIT-HOOK) ! BASE @ TBASE ! DECIMAL ;
|
||||
( -> ... the case is over: set its stack aside, top first )
|
||||
: -> ( i*x -- ) T-END 0
|
||||
BEGIN DEPTH 1 > WHILE
|
||||
DUP 16 < IF SWAP OVER TSTK + ! ELSE SWAP DROP 1 TBAD ! THEN
|
||||
1+ REPEAT
|
||||
16 MIN TDEP ! ;
|
||||
( ->ERR the case is over, and must have ended in an error )
|
||||
: ->ERR ( i*x -- ) T-END -1 TWANT ! T-CLEAR ;
|
||||
=====
|
||||
( ... }T the stack the case must have left, in order )
|
||||
: }T ( i*x -- )
|
||||
DEPTH TDEP @ = 0= IF 1 TBAD ! T-CLEAR EXIT THEN
|
||||
0 BEGIN DEPTH 1 > WHILE
|
||||
SWAP OVER TSTK + @ = 0= IF 1 TBAD ! THEN 1+ REPEAT DROP ;
|
||||
( len sum T= what the case must have printed )
|
||||
: T= ( len sum -- ) TSUM @ = 0= IF 1 TBAD ! THEN
|
||||
TLEN @ = 0= IF 1 TBAD ! THEN ;
|
||||
( the tally; a failure is an error, which ends the boot )
|
||||
: T-REPORT ( -- ) T-CLOSE 0 (CATCH) ! DECIMAL
|
||||
." PARITY:V4_POST tests=" T# @ T. ." pass=" TPASS @ T.
|
||||
." fail=" TFAIL @ T. CR
|
||||
TFAIL @ IF -1 NODE-ERROR ! THEN ;
|
||||
"""
|
||||
|
||||
|
||||
# ---- reading v3's case tables ----------------------------------------------
|
||||
|
||||
TOKEN = re.compile(r'''
|
||||
\s+ | /\*.*?\*/ | //[^\n]* |
|
||||
(?P<str>"(?:\\.|[^"\\])*") |
|
||||
(?P<punct>[{}(),;=\[\]&*]) |
|
||||
(?P<word>[A-Za-z0-9_.+\-]+)
|
||||
''', re.S | re.X)
|
||||
|
||||
ESCAPES = {"n": "\n", "t": "\t", "\\": "\\", '"': '"', "r": "\r", "0": "\0"}
|
||||
|
||||
|
||||
def unescape(lit):
|
||||
out, i, body = [], 0, lit[1:-1]
|
||||
while i < len(body):
|
||||
if body[i] == "\\" and i + 1 < len(body):
|
||||
out.append(ESCAPES.get(body[i + 1], body[i + 1]))
|
||||
i += 2
|
||||
else:
|
||||
out.append(body[i])
|
||||
i += 1
|
||||
return "".join(out)
|
||||
|
||||
|
||||
def tokens(text):
|
||||
pos, out = 0, []
|
||||
while pos < len(text):
|
||||
m = TOKEN.match(text, pos)
|
||||
if not m:
|
||||
pos += 1
|
||||
continue
|
||||
pos = m.end()
|
||||
if m.group("str"):
|
||||
value = unescape(m.group("str"))
|
||||
if out and out[-1][0] == "str": # adjacent literals join
|
||||
out[-1] = ("str", out[-1][1] + value)
|
||||
else:
|
||||
out.append(("str", value))
|
||||
elif m.group("punct"):
|
||||
out.append(("punct", m.group("punct")))
|
||||
elif m.group("word"):
|
||||
out.append(("word", m.group("word")))
|
||||
return out
|
||||
|
||||
|
||||
def parse_braces(toks, i):
|
||||
"""toks[i] is '{'; returns (nested list, index after the matching '}')."""
|
||||
items = []
|
||||
i += 1
|
||||
while toks[i] != ("punct", "}"):
|
||||
if toks[i] == ("punct", "{"):
|
||||
sub, i = parse_braces(toks, i)
|
||||
items.append(sub)
|
||||
elif toks[i] == ("punct", ","):
|
||||
i += 1
|
||||
else:
|
||||
items.append(toks[i][1] if toks[i][0] != "str" else ("s", toks[i][1]))
|
||||
i += 1
|
||||
return items, i + 1
|
||||
|
||||
|
||||
def read_module(path):
|
||||
"""Yields (word, case name, input, should_error) for every implemented case."""
|
||||
toks = tokens(open(path, encoding="utf-8", errors="replace").read())
|
||||
for i, t in enumerate(toks):
|
||||
if t != ("word", "WordTestSuite"):
|
||||
continue
|
||||
j = i
|
||||
while j < len(toks) and toks[j] != ("punct", "=") and toks[j] != ("punct", ";") and toks[j] != ("punct", "("):
|
||||
j += 1
|
||||
if j >= len(toks) or toks[j] != ("punct", "="):
|
||||
continue
|
||||
suites, _ = parse_braces(toks, j + 1)
|
||||
for suite in suites:
|
||||
if not isinstance(suite, list) or not suite or not isinstance(suite[0], tuple):
|
||||
continue
|
||||
word = suite[0][1]
|
||||
for case in suite[1]:
|
||||
if not isinstance(case, list) or len(case) < 6 or not isinstance(case[0], tuple):
|
||||
continue
|
||||
name, text = case[0][1], case[1][1]
|
||||
should_error, implemented = case[4] != "0", case[5] != "0"
|
||||
if implemented:
|
||||
yield word, name, text, should_error
|
||||
|
||||
|
||||
# ---- cutting a case's line to block lines ------------------------------------
|
||||
|
||||
STRING_OPENERS = {'."', 'S"', 'ABORT"', '.('}
|
||||
|
||||
|
||||
def atoms(text):
|
||||
"""The line as pieces that must each stay on one line: a word, or a word
|
||||
that takes text together with its text. None if the line has a new-line
|
||||
inside such a text."""
|
||||
out, i, n = [], 0, len(text)
|
||||
while i < n:
|
||||
if text[i].isspace():
|
||||
i += 1
|
||||
continue
|
||||
j = i
|
||||
while j < n and not text[j].isspace():
|
||||
j += 1
|
||||
word = text[i:j]
|
||||
upper = word.upper()
|
||||
if upper in STRING_OPENERS or upper == "(":
|
||||
close = ")" if upper in ("(", ".(") else '"'
|
||||
k = text.find(close, j + 1 if j < n else j)
|
||||
if k < 0:
|
||||
k = n - 1
|
||||
piece = text[i:k + 1]
|
||||
if "\n" in piece:
|
||||
return None
|
||||
out.append(piece)
|
||||
i = k + 1
|
||||
elif word == "\\":
|
||||
break # the rest of the line is a comment
|
||||
else:
|
||||
out.append(word)
|
||||
i = j
|
||||
return out
|
||||
|
||||
|
||||
def pack(prefix, pieces, width=LINE_MAX):
|
||||
"""Pieces into lines no longer than `width`, each begun with `prefix`
|
||||
(which may be empty). None if a piece cannot fit on a line."""
|
||||
head = [prefix] if prefix else []
|
||||
lines, current = [], []
|
||||
for piece in pieces:
|
||||
if len(" ".join(head + [piece])) > width:
|
||||
return None
|
||||
if current and len(" ".join(head + current + [piece])) > width:
|
||||
lines.append(current)
|
||||
current = []
|
||||
current.append(piece)
|
||||
if current:
|
||||
lines.append(current)
|
||||
return [" ".join(head + line) for line in lines]
|
||||
|
||||
|
||||
# A store to the search order, which v3's C test runner survives and a
|
||||
# running FORTH system does not.
|
||||
DAMAGES = re.compile(r"\b(CONTEXT|CURRENT)\s+!")
|
||||
|
||||
|
||||
def forgets_system_word(text):
|
||||
"""True if the line FORGETs a word it did not itself define. In a plain
|
||||
v3 session that takes the rest of the system with it, and v4 refuses."""
|
||||
words = text.split()
|
||||
for i, word in enumerate(words[:-1]):
|
||||
if word.upper() == "FORGET":
|
||||
target = words[i + 1]
|
||||
made = any(words[k] == target and k > 0 and words[k - 1].upper() in
|
||||
(":", "CREATE", "VARIABLE", "CONSTANT", "VOCABULARY") for k in range(i))
|
||||
if not made:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# ---- what v3 does --------------------------------------------------------------
|
||||
|
||||
ANSI = re.compile(r"\x1b\[[0-9;]*m")
|
||||
|
||||
|
||||
def run_v3(v3, cases):
|
||||
"""Runs the cases in one session. Returns a list, one entry per case:
|
||||
None if v3 did not get through it, else (error, stack, output)."""
|
||||
script = [": T| ; IMMEDIATE", ": TCLR BEGIN DEPTH WHILE DROP REPEAT ;"]
|
||||
for n, case in enumerate(cases):
|
||||
script.append('TCLR ." [[B%d]]"' % n)
|
||||
script.extend(case["lines"])
|
||||
script.append('." [[E%d]]" BASE @ DECIMAL .S BASE ! ." [[S%d]]"' % (n, n))
|
||||
script.append("BYE")
|
||||
done = subprocess.run([v3, "--log-none"], input="\n".join(script) + "\n", capture_output=True,
|
||||
text=True, errors="replace", timeout=600)
|
||||
text = ANSI.sub("", done.stdout)
|
||||
results = []
|
||||
for n, case in enumerate(cases):
|
||||
begin, mid, end = "[[B%d]] ok\nok> " % n, "ok> [[E%d]]" % n, "[[S%d]]" % n
|
||||
b = text.find(begin)
|
||||
e = text.find(mid, b) if b >= 0 else -1
|
||||
s = text.find(end, e) if e >= 0 else -1
|
||||
if b < 0 or e < 0 or s < 0:
|
||||
results.append(None)
|
||||
continue
|
||||
body = text[b + len(begin):e]
|
||||
# one "ok> " and one " ok" or " ERROR" for every line of the case
|
||||
chunks = body.split("ok> ")
|
||||
output, error, ok = "", False, True
|
||||
for chunk in chunks:
|
||||
if chunk.endswith(" ERROR\n"):
|
||||
output += chunk[:-len(" ERROR\n")]
|
||||
error = True
|
||||
elif chunk.endswith(" ok\n"):
|
||||
output += chunk[:-len(" ok\n")]
|
||||
else:
|
||||
ok = False
|
||||
m = re.match(r"<(\d+)>((?: -?\d+)*) \n", text[e + len(mid):s])
|
||||
if not ok or not m:
|
||||
results.append(None)
|
||||
continue
|
||||
stack = [int(v) for v in m.group(2).split()]
|
||||
results.append((error, stack[:-1], output)) # the last value is BASE
|
||||
return results
|
||||
|
||||
|
||||
def checksum(output):
|
||||
total = 0
|
||||
for ch in output.encode("latin-1", errors="replace"):
|
||||
total = (total * 31 + ch) & 0xFFFFFF
|
||||
return total
|
||||
|
||||
|
||||
# ---- writing the capsule -------------------------------------------------------
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--v3", default=os.path.join(ROOT, "lfs", "amd64", "starforth"))
|
||||
ap.add_argument("--report", default=None)
|
||||
args = ap.parse_args()
|
||||
|
||||
required, left_out, cases, seen = set(REQUIRED), [], [], {}
|
||||
for module in MODULES:
|
||||
for word, name, text, should_error in read_module(os.path.join(MODULE_DIR, module)):
|
||||
if word not in required:
|
||||
continue
|
||||
label = ("%s.%s" % (word, name))[:31]
|
||||
seen[label] = seen.get(label, 0) + 1
|
||||
if seen[label] > 1:
|
||||
label = (label[:28] + "~%d" % seen[label])[:31]
|
||||
if word in KEYBOARD:
|
||||
left_out.append((label, "reads the keyboard"))
|
||||
continue
|
||||
if forgets_system_word(text):
|
||||
left_out.append((label, "forgets a word of the system"))
|
||||
continue
|
||||
if DAMAGES.search(text.upper()):
|
||||
left_out.append((label, "damages the system on purpose"))
|
||||
continue
|
||||
pieces = atoms(text)
|
||||
lines = pack("T|", pieces) if pieces is not None else None
|
||||
if not lines:
|
||||
left_out.append((label, "a line cannot be cut to fit a block line"))
|
||||
continue
|
||||
cases.append({"label": label, "word": word, "text": text, "lines": lines, "should_error": should_error})
|
||||
|
||||
# v3 is run until every case left is one it gets through
|
||||
while True:
|
||||
results = run_v3(args.v3, cases)
|
||||
bad = [i for i, r in enumerate(results) if r is None]
|
||||
if not bad:
|
||||
break
|
||||
first = bad[0]
|
||||
left_out.append((cases[first]["label"], "v3 did not get through it in one session"))
|
||||
del cases[first]
|
||||
|
||||
blocks, current = [], []
|
||||
|
||||
def flush():
|
||||
if current:
|
||||
blocks.append(list(current))
|
||||
del current[:]
|
||||
|
||||
for part in HARNESS.strip("\n").split("=====\n"):
|
||||
current.extend(part.strip("\n").split("\n"))
|
||||
flush()
|
||||
|
||||
disagreements = []
|
||||
for case, (error, stack, output) in zip(cases, results):
|
||||
if error != case["should_error"]:
|
||||
disagreements.append((case["label"], "v3's table says %s, v3 %s"
|
||||
% ("error" if case["should_error"] else "no error",
|
||||
"raised one" if error else "raised none")))
|
||||
lines = ["T{ " + case["label"]] + case["lines"]
|
||||
if error:
|
||||
lines.append("->ERR")
|
||||
else:
|
||||
tail = ["->"] + [str(v) for v in stack] + ["}T", str(len(output)), str(checksum(output)), "T="]
|
||||
lines.extend(pack("", tail))
|
||||
if len(current) + len(lines) > 16:
|
||||
flush()
|
||||
current.extend(lines)
|
||||
flush()
|
||||
blocks.append(["T-REPORT", "FORGET T# DECIMAL"])
|
||||
|
||||
with open(OUTPUT, "w", encoding="ascii") as out:
|
||||
for k, block in enumerate(blocks):
|
||||
assert len(block) <= 16, block
|
||||
out.write("Block %d\n" % (FIRST_BLOCK + k))
|
||||
for line in block:
|
||||
assert len(line) <= LINE_MAX, line
|
||||
out.write(line + "\n")
|
||||
|
||||
tested = sorted({c["word"] for c in cases})
|
||||
untested = [w for w in REQUIRED if w not in set(tested)]
|
||||
report = ["POST cases: %d, in %d blocks (%d to %d)" % (len(cases), len(blocks), FIRST_BLOCK, FIRST_BLOCK + len(blocks) - 1),
|
||||
"Required words with at least one case: %d of %d" % (len(tested), len(REQUIRED)),
|
||||
"Required words with no case: " + " ".join(untested), "",
|
||||
"Left out (%d):" % len(left_out)]
|
||||
report += [" %-32s %s" % item for item in left_out]
|
||||
report += ["", "v3 did not do what its own table expects (%d):" % len(disagreements)]
|
||||
report += [" %-32s %s" % item for item in disagreements]
|
||||
text = "\n".join(report) + "\n"
|
||||
if args.report:
|
||||
open(args.report, "w").write(text)
|
||||
sys.stdout.write(text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user