From 9fe95ef12b6510d428df078917d696712a69e837 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 6 Nov 2020 20:02:53 -0800 Subject: [PATCH] Add tool for viewing memory https://justine.storage.googleapis.com/memzoom/index.html --- README.md | 307 ------- ape/ape.S | 10 +- examples/examples.mk | 5 + libc/bits/hilbert.c | 4 +- libc/tinymath/log2.S | 6 +- libc/tinymath/log2f.S | 10 +- libc/tinymath/log2l.S | 6 +- tool/build/blinkenlights.c | 553 +++++------- tool/build/emubin/lisp.h | 180 ---- tool/build/emubin/lisp.lisp | 105 --- tool/build/emubin/lispelf.S | 23 - tool/build/emubin/lispstart.S | 51 -- tool/build/lib/buffer.c | 22 +- tool/build/lib/elfwriter.c | 2 + tool/build/lib/machine.c | 8 +- tool/build/{emubin/lisp.lds => lib/pml4t.c} | 74 +- tool/build/lib/pml4t.h | 11 + tool/build/lib/xmmtype.c | 179 ++++ tool/build/lib/xmmtype.h | 21 + tool/build/package.c | 2 + tool/viz/memzoom.c | 940 ++++++++++++++++++++ tool/viz/printimage.c | 20 +- 22 files changed, 1511 insertions(+), 1028 deletions(-) delete mode 100644 tool/build/emubin/lisp.h delete mode 100644 tool/build/emubin/lisp.lisp delete mode 100644 tool/build/emubin/lispelf.S delete mode 100644 tool/build/emubin/lispstart.S rename tool/build/{emubin/lisp.lds => lib/pml4t.c} (51%) create mode 100644 tool/build/lib/xmmtype.c create mode 100644 tool/build/lib/xmmtype.h create mode 100644 tool/viz/memzoom.c diff --git a/README.md b/README.md index cab548e3..1a1bec24 100644 --- a/README.md +++ b/README.md @@ -5,310 +5,3 @@ Fast portable static native textmode executable containers. For an introduction to this project, please read the αcτµαlly pδrταblε εxεcµταblε blog post. - -Cosmopolitan builds run natively on most platforms without dependencies, -because it implements the subset of the C library, compiler runtimes and -system call interfaces that've achieved near universal consensus amongst -all major platforms, e.g. Linux/BSD/XNU/NT. Containerization is achieved -by having binaries also be ZIP files. Modern static stock GNU toolchains -are provided in a hermetic mono repo for the best historical determinism - -Here's how you can get started by printing cat videos inside a terminal: - - make -j8 o//tool/viz/printvideo.com - wget https://justine.storage.googleapis.com/cats.mpg - o//tool/viz/printvideo.com cats.mpg - unzip -vl o//tool/viz/printvideo.com - -Cosmopolitan provides a native development environment similar to those -currently being offered by RedHat, Google, Apple, Microsoft, etc. We're -different in two ways: (1) we're not a platform therefore we don't have -any commercial interest in making our tooling work better on one rather -than another; and (2) we cater primarily towards features having gained -cross-platform agreement. Goal is software that stands the test of time -without the costs and restrictions cross-platform distribution entails. - -That makes Cosmopolitan an excellent fit for writing small CLI programs -that do things like matrix multiplication relu stdio as a subprocess or -perhaps a web server having the minimum surface area that you require. - -## Getting Started - -Just clone the repository and put your own folder in it. Please choose a -name that's based on a .com or .org domain name registration you control -which is scout's honor but could change to verify TXT records in future. - -We provide a script that makes it easy to start a new package: - - examples/package/new.sh com/github/user/project - emacs com/github/user/project/program.c - make o//com/github/user/project/program.com - o//com/github/user/project/program.com - -Please note GNU Make is awesome. Little known fact: make is a functional -programming language. We improved upon it too! In [tool/build/package.c] -which performs strict dependency checking, to correct Google's published -mistakes c. 2006 which was when they switched from using a GNU Make repo -in favor of an inhouse derivative called Blaze which does graph checking -thereby allowing the repository to grow gracefully with any requirements - -## Performance - -Your C Standard Library is designed to be competitive with glibc, which -has historically been the best. Routines like [libc/nexgen32e/memcpy.S] -are usually accompanied by microbenchmarks to demonstrate their merits. - -Where GNU, LLVM and MSVC got lazy is intrinsics. Cosmopolitan does that -better. Your [ansitrinsics library] makes a 10x speedup so much easier, -using Intel's new instructions, in such a way that only allows Intel to -leverage their patents which have knowable expiry; rather than compiler -intrinsics API copyrights, which might never expire like Walt Disney IP - -See [dsp/scale/cdecimate2xuint8x8.c] and [tool/viz/lib/ycbcr2rgb3.c] as -an example, of how 4k video convolutions needed to print cat videos can -be done from a single core without threads on a cheap computer, without -sacrificing backwards compatibility due to excellent microarchitectural -dispatch like [libc/nexgen32e/kcpuids.S], [libc/nexgen32e/x86feature.h] - -Furthermore Cosmopolitan provides you with Intel's official instruction -length decoder Xed ravaged down to 3kb in size using Tim Patterson code -stunts. So you can absolutely code high-performance lightweight fabless -x86 microprocessors using any hobbyist board without royalties, because -Xed tells us which parts of the encoding space now belong to the people. -Please see [third_party/xed/x86ild.greg.c] to learn more. - -## Integrated Development Environment - -Your Cosmopolitan IDE is based on whichever editor you love most. Emacs -configs are provided, showing how `make tags` can be used to automate -certain toil, such as adding include lines by typing `C-c C-h` over a -symbol. We recommend trying the following: - - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" - sudo apt install gdb ragel ctags clang-format-10 - git clone git@github.com:jart/cosmopolitan.git && cd cosmopolitan - tool/scripts/install-emacs.sh # Emacs 26.1 has a bug - tool/scripts/configure-emacs.sh # adds load statements - make tags # index all the symbol - emacs # for power and glory! - -See [tool/emacs/cosmo-stuff.el] for further details. Further note that -this codebase might seem to have unusual numbers of include statements -quoted and vendored code, but that's actually why the tools work since -it gives them easy perfect knowledge of what exists, thus performance. - -## Specimen - -Cosmopolitan encodes binaries respecting the intersection of reasonable -platform requirements. RADIX-256 disassembly of [examples/life.c] below -should explain how easy it is to do pe+sh+elf+macho+bootloader overlays -enabling gnu ld.bfd to produce a simple portable 12kb .com program file - -Please send feedback and concerns to since we would -love to do an even better job. Please also let us know if some goofball -is distributing without bundling their source code, so we can reach out -and ask if they would like to purchase a commercial license. - - make -j10 -O MODE=tiny CPPFLAGS=-DIM_FEELING_NAUGHTY - o/tiny/tool/viz/bing.com /dev/null◙elif exec 7<> “$o“; then◙printf ‘╲ - 177ELF╲2╲1╲1╲011╲0╲0╲0╲0╲0╲0╲0╲0╲2╲0╲076╲0╲1╲0╲0╲0╲134╲022╲100╲0 - 00╲000╲000╲000╲000╲150╲012╲000╲000╲000╲000╲000╲000╲000╲000╲000╲0 - 00╲000╲000╲000╲000╲0╲0╲0╲0╲100╲0╲070╲0╲004╲000╲0╲0╲000╲000╲000╲0 - 00‘ >&7◙exec 7<&-◙fi◙exec “$@“◙R=$⁇◙if [ $R -eq 126 ] && [ “$(un - ame -m)“ != x86_64 ]; then◙if Q=“$(command -v qemu-x86_64)“; the - n◙exec “$Q“ “$@“◙else◙echo error: need qemu-x86_64 >&2◙fi◙fi◙exi - t $R◙αcτμαlly pδrταblε εxεcμταblε♪◙ error:  ♪◙ cpuid oldskool ds - knfo e820 nomem nolong hello◙ ♀  Cf☼▼D  8 ╕D      f☼▼D           - λλ   Ü☼ λλ   Æ☼ λλ   Ü╧ λλ   Æ╧ λλ   ¢» λλ   ô» ☻░¡←  ☺ ■OQΣ≡♦   -   ►  0►  @► ►♣  =☻░¡+☼à↑♪  j ¥▓@☼ └âα■☼“└fΩW@  ÉÉÉÉUëσΦ§♪Φ↓ ┐• î - ♠▬2ú↑2Φ(☺┐EDΦÑ Φ╨♀Φ→☻Uëσ╣♦ ╛ 0¼ê┬¼ê╞à╥t♀QVë╫╛€DΦ○ ^YâΘ☺uσ]├Uëσë· - à╥t↑RV1╔▒♥☺╩¼^♀ÇεZ¼εâ┬☺âΘ☺y÷]├UëσΦ↕ Φ  Uëσ┐ 0╛♦ ΦÇ ΦÉ☺Uëσï╖☻0à÷u - ♦ï6 01└PV╕lDPVWV╕dDP_àλt♠^Φ♦ δ⌡]├UëσWVΦ♂ ^_à÷t♥Φ↨ ]├Uëσë■─>▬2Φ╕  - î♠▬2ú↑2]├UëσSë√ç▐¼ç▐ä└t↑ë╟VP╕  δ◘XΦ.   δ♦XΦ( ^δ▀[]├ë±ë■1╥¼ê┬¼ê╞à - └t◄â┬♣┤@∞ α≤Ét∙âΘ☺uσ├PQRë≥â┬♣┤ ∞ αu♦≤Éδ≈ë°ë≥εZYX├UëσS┤╕░ Ä└ë°<♥t - ☻0φ1λj X═►┤☺░ ╡ ▒ ═►┤►░♥╖ │ ═►1└[]├Uëσâ∞►ûë∙ëμëτ¬ë╧j☺Zδ♫V¼ä└u√ë≥ - ^)≥UëσSë╤ë·ÇΓ ÇμÇÇ┬áÇ╓☼╖ │á9·t)w↕¼<◙t↕<♪t↕¬░•¬âΘ☺uΦë°[]├☺▀δ≥ë°R1 - ╥≈√)╫ZδμPQRVë▐P╕  δ◘XΦ♫   δ♦XΦ◘ ë╟^ZYXδ╞≈╥ë∙Çß ÇσÇç╧)±Q)∙ë■☺╬╕   - ▲•≤ñX├Uëσ╕ S1█═§r→ü√MPu¶╕☺S1█═§1█1╔╕•S│☺▒♥═§Φ╢◙UëσΦ↔ Φy☺┐ ►╛  Φz -  r○Φ╟ Φ∞ Φ‘☻╕àDΦ♀■Uëσ£X% puMf£fXfë┴f╗    f1╪fPf¥f£fXf9┴t:f!╪fPf¥ - f┐   Çfë°fG☼óf9°|∟fë°☼óf┐    f!·f9·u○1└]├╕uDδ◙╕ÉDδ♣╕oDδ Φú²Uëσfh - PAMSS┴∩♦Ä╟f1λf1█f╕ Φ  f╣↑   fïVⁿ═§r&f;Fⁿu à╔t♫â∙§r♠÷E¶☺u♥â╟↑fà█t - ♦9≈r╦ë°[╔├∙δ·Uëσ·☼☺▬¿D☼ └♀☺☼“└δ ╣  Äß$■☼“└fΩrH    √]├UëσSf╛ @  f - ╗  ► f╣↑   f┴ß○fâ╩ⁿfâ┬♦f9╤t♫dgfï♦▬dgfë♦‼δΘgfì∟‼┐  ╕ @Ä└ï♫@2ï▬B2à - λt+ë°S1█ΦS°[)╟Që┴┴ß○1÷&fï♦dgfë♥fâ├♦â╞♦âΘ♦uδYδ╤[]├·▲1└Ä└HÄ╪┐ ♣╛►♣ - &è♣Pè♦P&╞♣ ╞♦λ&Ç=λXê♦X&ê♣▼u@╕☺ Φ, ░¡μdΦ% ░╨μdΦ% Σ`PΦ↑ ░╤μdΦ◄ X♀☻ - μ`Φ○ ░«μdΦ☻ δúΣd¿☻u·├Σd¿☺t·├√├Uëσ▲╕ lÄ╪f╟♠ 0♥α♠ f╟♠  ♥╨♠ f╟♠ ►♥└ - ♠ ╣ ☺f╕♥   1÷fë♦f♣ ►  â╞◘âΘ☺u∩▼f╟♠ 2 └♠ f╕ ≡♠ ☼“╪]├·☼☺▲02Φóλ☼ αf - ♪á☻  ☼“αf╣Ç  └☼2f♪☺☺  ☼0☼☺▬¿D☼ └f♪♥  Çfâα√☼“└Ω≥I( ╕0   Ä╪ÄαÄΦ1╥δ -  HâΣ≡1φ1λΦ]•  ┐ ►  Φ{•  ┐ ►  ╛ ≡♠ ║ 2  Φ≡♣  ┐ùD  ï4% 0  Φ╠√λλ┐ 0 -   ╛♦   Φτ√λλΘΓ•  Hì§█•  Φλ•  Θ╤•  É☼▼D  ☺   ♣             @      -   ►                      ►      ☺   ♠             @       ►      -  ►               ►      Qσtd♠                                    -         ►       ♦   ♦   P♂      P♂@     P♂►     ↑       ↑        - ◘       É☼▼Ç    ◘   ♦   ☺   OpenBSD     É☼▼Ç    PE  då☻ k↕d╲     -     ≡ #☻♂☻♫☼            ╞¶        @      ►   ►  ♠       ♠        -  @   ►      ♥  ☺  ►       ♥       ◘      ►          ►            - ä←  (                                                            -                         ►   @                           .text    -  ►   ►   ►   ►              `  p.data            ►               -     └  └É☼▼Ç    ╧·φ■•  ☺♥   ☻   ♣   ÿ☻  ☺       ↓   H   __PAGEZE - RO                                                      ↓   ÿ    - __TEXT            @                             •   ♣   ☺        - __text          __TEXT           ►@      ►       ►  ♀            -  ♦              ↓   Φ   __DATA            @                      -  ►      •   ♥   ☻       __data          __DATA            @      -  ►          ♀                           __bss           __DATA   -          0@      ►          ♀           ☺               ←   ↑    - B)→☺&¿◘ºB)→☺&¿◘º♣   ╕   ♦   *             @                      -                                                                  -                                 S↕@                              -         Éf.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä -      f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f☼▼ä      - ZAR╕    Hà└t◙Hà└t♣Θ»♦  Θ@☻  UHë╤HëσAWIë≈AVA╛  @ AUIë²ATA╝  ► SHë - √Hâ∞↑Hâ{◘ ☼ä╕   ïS►Hë╪Hâ├↑λ╩t○Hâ{◘ uδδ♥Hë├L9#L☼C#Iü─λ☼  IüΣ ≡λλH - ïC◘H♥♥H% ≡λλI9─snIïU◘Hà╥t↓Aâ}►☺u♠Iâ┼↑δΩIïE H☺╨L9αrεIïE L9αw◄H☺╨L - 9αv○Lìáλ☼  δ½Lë·Lë≈╛♥   HëM╚Φ6   LëΓHïM╚Iü╞ ►  Hâ╩♥Iü─ ►  Hë►δÇH - â├↑Θ=λλλHâ─↑[A╲A]A^A_]├I╣ ≡λλλλ♥ Ië╚╣‘   Hë°λ╬H╙Φ%λ☺  â■λu♣Hì♦┬├ - Hì¶┬Hâ: u‼Iï H- ►  Ië Hâ╚♥Hë☻Hï☻âΘ○L!╚Hë┬δ╛U╣ 2  ║ ≡♠ ╛♥   HëσSH - ë√PΦÅλλλHâ ■☼☺;Z[]├1÷ë≡Hk└↑Hâ|•◘ t♦λ╞δεA╕☺   HìW↑A9≡r☺├UHëσATSLï - ◙HïZ◘Hë╤Dë└DïZ►DïR¶Aë─λ╚L;IΦt→☼►AΦLïa°HâΘ↑☼◄A↑Lëa(à└u▌δ♥DëαHk└↑A - λ└Hâ┬↑H☺°Lë◘HëX◘DëX►DëP¶A9≡rí[A╲]├1└├UëσSç█[fÉ╠·⌠δ²Uëσâ∞◘U^ì~°j◘ - Y1└≤¬·☼☺^°☼♂δ≈Uëσ]├╞♣ª↔  ◘δ►HàλH☼Eτt•╞♣ö↔   Lc$$Lìl$◘NìtΣ↑╕“↕@ ┐ - ► @ ╣P @ H)∙┴Θ♥≤H½1└â╔λLë≈≥H»IëλΘ╧   UHëσ┐ 0@ ╛°←@ ╣00@ HìA►Hë☺╟ - A◘ ♥  SV÷•◘u<÷• u!÷•♦u◄Iâ⁇ t!j j☺╛ⁿ←@ δ*j“j♦╛☻∟@ δ▼j0j ╛∙←@ δ¶j* - j►╛λ←@ δ○jEj◘╛♦∟@ ╣q↓@ XH½XH☺╚H½W┐↑0@ Iâ╔λ╗(0@ H9▀s51╔1╥¼Ië└Aâα⌂ - I╙αâ┴•L○┬ä└xδ¿@t○Lë╚H╙αH○┬Hë╨Hâ⁇ H☼E•H½δ╞_^[╔├╕*   ├HâΣ≡1φ╗  @ Φ - !λλλâ♪┴▼  ☺╕◘ @ ╣◘ @ H9┴t♀PQλ►YXHâ└◘δ∩ÉLëτLëεLë≥Φ╣λλλë╟Φ    UHëσ - ATAëⁿ1λPΦr   DëτΦö♠  1÷1╥UHëσAW╣00@ Ië╧Iï•IïO◘Hà╔t∟HâΘ↑Hë¶◘Hët◘◘ - Hë|◘►IëO◘1└A_]├╣    Hà╔t≥PWVj!_j►^λ╤^_YHà└t▀I╟└ ♥  Ië•Jë♀ Lë┴δ┤U - HëσAVAUATHï5α←  Ië■Ië⌠j YH¡HÆH¡HùH¡Hà└t↑Mà÷δ♣L9≥u♫VQQλ╨YY^1└HëF° - âΘ☺u╘H¡Hà└t◄Mà÷t○PLëτΦfδ┐λ^δ╢A╲Mà÷u←╕► @ ╣► @ HâΦ◘H9╚|◘PQλ►YXδ∩A - ]A^]├╠U╣ ◘  1└HëσAWAVAUATSHü∞Hα  Hëà└▼λλHëà╚▼λλλ§C♂  Hâ─ à└uGHâ∞ - H╟┴⌠λλλ맓♂  Hâ─↑A╕♠   Lìì╨⌂λλj Hë┴║⌐→@ Hâ∞ λ§♪♂  XZ╣☺   λ§╨◙   - Hâ─ Hâ∞ j♦Xë♣»→  λ§╔◙  Ië─λ§╚◙  LëτHâ─ A╕ ☻  Hìì╨/λλ║λ⁇  Hì╡╤⁇λλ - Ië┼Φ╙☺  Aë─1└Hïì╨/λλH☺┴è◄ä╥t♪Ç·╲u♥╞☺/Hλ└δπA☼╖E f=λ╫w♪ëà╝▼λλ╕☺    - δ☼Hì╡╝▼λλLë∩Φ0♦  ë└Hìì╨⌂λλE1└1█H☺└Ië╦LìU╬A╛²⌂  IìT♣ Hì╡╝▼λλâ╜╝▼λ - λ ☼äÅ   Iλ└Iü°λ☺  w↕L9╤Hë╪H☼B┴Jëä┼╚▼λλDïì╝▼λλIc┴Aâ∙⌂v◘Dë╧ΦÉ♥  L9 - ╤s♀Hλ┴êAλH┴Φ◘u∩☼╖☻f=λ╫w♪ëà╝▼λλ╕☺   δ◘Hë╫Φö♥  ë└H☺└H☺┬Eà╔u¼Hë╚L)╪ - H=²⌂  I☼G╞╞ä♣╨⌂λλ ΘdλλλL9╤s♠╞☺ Hλ┴L)┘╕■⌂  Lì╡╨▼λλHü∙■⌂  Lì╜└▼λλH - ☼G╚Iü°λ☺  ╕λ☺  L☼G└Hâ∞ ╞ä♪╨⌂λλ LëΘLì¡╨/λλJ╟ä┼╨▼λλ    λ§↔○  Θtⁿλλ - Hë·Hï⁇☼╖•f=λ╫w◙ëB↑╕☺   δ○Hìr↑Φ▀☻  ë└H☺└H☺☻├Hë·Hc╞ë≈LïB►â■⌂v♣Φì☻  -  HïJ◘I9╚v►Hìq☺Hër◘ê☺H┴Φ◘uτ├UHì♦▬Ië╙Më┬HëσAWI┐ &  ☺   AVAUIë⌡ATS1 - █Hâ∞8Hë}░Hì}░HëM¿Hëu╕HëE└Φbλλλâ}╚ t↔ïE╚à└t▬â° w╲I☼ú╟sVHì}░ΦAλλλδ - π1÷Hì}░Φ_λλλMà█t↨HïE╕Iλ╦L)ΦL9╪I☼G├A╞D♣  Mà╥☼äf☺  Iλ╩HïE¿I9┌L☼G╙J - ╟♦╨    ΘK☺  Hλ├L9╙s§HïE╕H;E└r☻1└HïU¿HëD┌°E1÷ïu╚à÷☼ä►☺  Eä÷u¶â■ w - ☼I☼ú≈☼âσ   Θ≈   â■“t○â■╲☼à╥   E1Σâ}╚╲u♫Hì}░Iλ─Φì■λλδ∞E1╔â}╚“u♫Hì - }░Φy■λλIλ┴δ∞LëαMà╔u↓Iλ╠IâⁿλtÅ╛╲   Hì}░ΦÇ■λλδτHâ°☺v∟╛╲   Hì}░HëEá - Φf■λλHïEáHâΦ☻δ▐AÇΣ☺t↨╛“   Hì}░ΦH■λλIλ╔☼ä@λλλAÇ■☺A╛♥   Iâ┘ Mìa☺M9 - ⌠r¶╛“   Hì}░Iâ╞♥Φ▬■λλδτ1╥╣♥   Lë╚H≈±Hà╥A☼ö╞Θⁿ■λλHì}░Φ≥²λλHì}░Φ╛² - λλΘσ■λλ1÷Hì}░Φ┘²λλΘG■λλHâ─8ë╪[A╲A]A^A_]├╠Hì♣╪↓  ├☼┐└à└x←Ië╩☼♣H=☺ - ≡λλs☺├≈╪ë♣║↓  jλX∙├ï♣⌂▬  δφH┴Φ0δ•H┴Φ ☼╖└f=λ☼sσIë╩☼♣r╙├Aë├┴Φ►%λ☼  -  A┴δ∟A┴π↑D○╪δ┌QRëλ1└âλ⌂v“☼╜╧║┐→@ ïLJ≥ë·┴∩♠ÇΓ⁇♀Ç◘╨H┴α◘■╔u∞◘ΦH○°ZY - ├U1└HëσWVSQRë┬ë├λ└☼╖¶Wë╤füß ⁿfü∙ ▄tΦfü∙ ╪t♦ë▬δ,☼╖♦Gë┴füß ⁿfü∙ ▄t - ♂╟♠²λ  â╚λδ☼┴Γ◙ìä☻ $áⁿë♠ìC☻ZY[^_]├f☼▼D  Éâ♪▄↑  ♦÷♣맠 ♦t♪@☼╢╧λ§ì - ♣  δ°╠ï♣ö§  ☼♣·☼☺∟%Ü→@ ⌠δ²        f☼▼D  Énodll◙ KernelBase.dll ☺ - └☺└☺└☺└☻α☻α☻α☻α☻α♥≡♥≡♥≡♥≡♥≡♦°♦°♦°♦°♦°♣ⁿ♣ⁿ♣ⁿ♣ⁿ♣ⁿ♣ⁿÉÉ☼▼D  ⁇♣ExitPr - ocess æ☺FreeEnvironmentStringsW ╜☺GetCommandLineW ‼☻GetEnvironme - ntStringsW  ╘☻GetStdHandle  ╫♣SetDefaultDllDirectories  ▼•WriteF - ile ░←          ░→  ►                       ☼▼@ °→      ♠←       - ←      2←      L←      ╲←      x←              É☼▼Ç    É╬ ☺&τ☺╬ -  ☺☺⌂╬ üÇÇ►f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ - ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä    -   f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f. - ☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä  -     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä      - f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ - ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä    -   f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f. - ☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä  -     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä      - f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ - ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä    -   f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f. - ☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä  -     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä      - f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     f.☼▼ä     ☼▼@  -   @             °→      ♠←       ←      2←      L←      ╲←       - x←                                                               - -See also `build/objdump -xd o/tiny/examples/life.com.dbg | less` to view -assembly and the linker glue in [ape/ape.lds] that makes it all possible - -## Licensing - -Cosmopolitan is Free Software licensed under the GPLv2. The build config -**will embed all linked sources inside your binaries** so the compliance -is easy while facilitating trust and transparency similar to JavaScript. -You can audit your source filesystem using ZIP GUIs e.g. Win10, InfoZip. -That works easiest by changing the filename extension from .com to .zip. - -### Commercial Support - -If you want to be able to distribute binaries in binary only form, then -please send $1,000 to Justine Tunney on PayPal, for -a license lasting 1 year. This README will be updated in the event that -this needs to change. Please reach out if there's anything you need. - -## Contributing - -We'd love to accept your patches! Before we can take them, we have to -jump through one legal hurdle. Please write an email to Justine Tunney - saying you agree to give her copyright ownership to -any changes you contribute to Cosmopolitan. We need to do that in order -to dual license Cosmopolitan. Otherwise we can't create incentives that -encourage corporations to share their source code with the community. - -## Volunteering - -We also need volunteers who can help us further stabilize System Five's -application binary interface. See our ABI scripts [libc/sysv/consts.sh] -and [libc/sysv/syscalls.sh]. Magic numbers are usually stabler than API -interfaces cf. NPM but we should ideally have fewer of them, similar to -how SI has sought to have fewer defining physics constants. - -## About - -Cosmopolitan mostly stands on the shoulders of giants and has few novel -ideas, aside from taking care of low-level build system toil, so coding -can become more beautifully pleasant. - -Cosmopolitan is maintained by Justine Tunney, who previously worked on -projects like [TensorFlow], [Operation Rosehub], [Nomulus], and Google's -tape backups SRE team. She's also helped activists by operating the -[Occupy Wall Street] website. Justine Tunney currently isn't on the -payroll of any company. She's been focusing on Cosmopolitan because she -wants to give back to Free Software which helped her be successful. See -her [LinkedIn] profile for further details on her professional history. - - -[LinkedIn]: https://www.linkedin.com/in/jtunney -[Nomulus]: https://github.com/google/nomulus -[Occupy Wall Street]: https://www.newyorker.com/magazine/2011/11/28/pre-occupied -[Operation Rosehub]: https://opensource.googleblog.com/2017/03/operation-rosehub.html -[TensorFlow]: https://github.com/tensorflow/tensorflow -[ansitrinsics library]: libc/intrin -[ape/ape.lds]: ape/ape.lds -[dsp/scale/cdecimate2xuint8x8.c]: dsp/scale/cdecimate2xuint8x8.c -[examples/life.c]: examples/life.c -[libc/nexgen32e/kcpuids.S]: libc/nexgen32e/kcpuids.S -[libc/nexgen32e/memcpy.S]: libc/nexgen32e/memcpy.S -[libc/nexgen32e/x86feature.h]: libc/nexgen32e/x86feature.h -[libc/sysv/consts.sh]: libc/sysv/consts.sh -[libc/sysv/syscalls.sh]: libc/sysv/syscalls.sh -[third_party/xed/x86ild.greg.c]: third_party/xed/x86ild.greg.c -[tool/build/package.c]: tool/build/package.c -[tool/emacs/cosmo-stuff.el]: tool/emacs/cosmo-stuff.el -[tool/viz/lib/ycbcr2rgb3.c]: tool/viz/lib/ycbcr2rgb3.c diff --git a/ape/ape.S b/ape/ape.S index acc1d2f3..2f26782f 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -1631,7 +1631,7 @@ long: push $GDT_LONG_DATA xor %ebp,%ebp mov $REAL_STACK_FRAME+FRAMESIZE,%esp call __map_image - mov $_metal,%eax + ezlea _metal,ax jmp *%rax .endfn long @@ -1646,8 +1646,12 @@ _metal: mov $.Lape.bss.vaddr,%edi mov $.Lape.bss.memsz,%ecx rep stosb - movb $METAL,hostos(%rip) - push $0 # auxv + .weak hostos + ezlea hostos,ax + test %rax,%rax + jz 1f + movb $METAL,(%rax) +1: push $0 # auxv push $0 push $0 # envp push $0 # auxv diff --git a/examples/examples.mk b/examples/examples.mk index f3417d58..48c64fdd 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -108,6 +108,11 @@ o/$(MODE)/examples/%.elf: \ $(ELF) @$(ELFLINK) +o/$(MODE)/examples/tiny-raw-linux-tutorial.elf: \ + o/$(MODE)/examples/tiny-raw-linux-tutorial.o \ + $(ELF) + @$(ELFLINK) -N -z max-page-size=0x10 + $(EXAMPLES_OBJS): examples/examples.mk o/$(MODE)/examples/hellojs.com.dbg: \ diff --git a/libc/bits/hilbert.c b/libc/bits/hilbert.c index c6074d54..b2ed8d7c 100644 --- a/libc/bits/hilbert.c +++ b/libc/bits/hilbert.c @@ -43,12 +43,12 @@ long hilbert(long n, long y, long x) { long d, s, ry, rx; d = 0; for (s = n / 2; s > 0; s /= 2) { - rx = (x & s) > 0; ry = (y & s) > 0; + rx = (x & s) > 0; d += s * s * ((3 * rx) ^ ry); m = RotateQuadrant(n, y, x, ry, rx); - x = m.dx; y = m.ax; + x = m.dx; } return d; } diff --git a/libc/tinymath/log2.S b/libc/tinymath/log2.S index 249cc8e7..b9640c62 100644 --- a/libc/tinymath/log2.S +++ b/libc/tinymath/log2.S @@ -24,7 +24,8 @@ / / @param 𝑥 is a double passed in the lower quadword of %xmm0 / @return result in lower quadword of %xmm0 -log2: push %rbp +tinymath_log2: + push %rbp mov %rsp,%rbp .profilable push %rax @@ -36,4 +37,5 @@ log2: push %rbp movsd -8(%rbp),%xmm0 leave ret - .endfn log2,globl + .endfn tinymath_log2,globl + .alias tinymath_log2,log2 diff --git a/libc/tinymath/log2f.S b/libc/tinymath/log2f.S index b2b16385..ef30475c 100644 --- a/libc/tinymath/log2f.S +++ b/libc/tinymath/log2f.S @@ -20,7 +20,12 @@ #include "libc/macros.h" .source __FILE__ -log2f: push %rbp +/ Calculates log₂𝑥. +/ +/ @param 𝑥 is a float passed in the lower quarter of %xmm0 +/ @return result in lower quarter of %xmm0 +tinymath_log2f: + push %rbp mov %rsp,%rbp .profilable push %rax @@ -32,4 +37,5 @@ log2f: push %rbp movss 4(%rsp),%xmm0 leave ret - .endfn log2f,globl + .endfn tinymath_log2f,globl + .alias tinymath_log2f,log2f diff --git a/libc/tinymath/log2l.S b/libc/tinymath/log2l.S index f739da61..fdd70dd5 100644 --- a/libc/tinymath/log2l.S +++ b/libc/tinymath/log2l.S @@ -25,7 +25,8 @@ / @param 𝑥 is an 80-bit long double passed on stack in 16-bytes / @return result in %st / @see ilogbl() -log2l: push %rbp +tinymath_log2l: + push %rbp mov %rsp,%rbp .profilable fld1 @@ -33,4 +34,5 @@ log2l: push %rbp fyl2x pop %rbp ret - .endfn log2l,globl + .endfn tinymath_log2l,globl + .alias tinymath_log2l,log2l diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index ea47f0c3..36b4f3d8 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "dsp/scale/cdecimate2xuint8x8.h" #include "dsp/tty/tty.h" #include "libc/alg/arraylist2.h" #include "libc/assert.h" @@ -90,6 +91,7 @@ #include "tool/build/lib/stats.h" #include "tool/build/lib/syscall.h" #include "tool/build/lib/throw.h" +#include "tool/build/lib/xmmtype.h" #define USAGE \ " [-?HhrRstv] [ROM] [ARGS...]\n\ @@ -102,6 +104,7 @@ DESCRIPTION\n\ FLAGS\n\ \n\ -h help\n\ + -z zoom\n\ -v verbosity\n\ -r real mode\n\ -s statistics\n\ @@ -122,8 +125,10 @@ FEATURES\n\ 8086, 8087, i386, x86_64, SSE3, SSSE3, POPCNT, MDA, CGA, TTY\n\ \n" -#define DUMPWIDTH 64 -#define DISPWIDTH 80 +#define MAXZOOM 16 +#define DUMPWIDTH 64 +#define DISPWIDTH 80 +#define WHEELDELTA 1 #define RESTART 0x001 #define REDRAW 0x002 @@ -138,28 +143,31 @@ FEATURES\n\ #define EXIT 0x400 #define ALARM 0x800 -#define kXmmIntegral 0 -#define kXmmDouble 1 -#define kXmmFloat 2 - #define kXmmDecimal 0 #define kXmmHex 1 #define kXmmChar 2 -#define kMouseLeftDown 0 -#define kMouseMiddleDown 1 -#define kMouseRightDown 2 -#define kMouseLeftUp 4 -#define kMouseMiddleUp 5 -#define kMouseRightUp 6 -#define kMouseLeftDrag 32 -#define kMouseMiddleDrag 33 -#define kMouseRightDrag 34 -#define kMouseWheelUp 64 -#define kMouseWheelDown 65 +#define kMouseLeftDown 0 +#define kMouseMiddleDown 1 +#define kMouseRightDown 2 +#define kMouseLeftUp 4 +#define kMouseMiddleUp 5 +#define kMouseRightUp 6 +#define kMouseLeftDrag 32 +#define kMouseMiddleDrag 33 +#define kMouseRightDrag 34 +#define kMouseWheelUp 64 +#define kMouseWheelDown 65 +#define kMouseCtrlWheelUp 80 +#define kMouseCtrlWheelDown 81 #define CTRL(C) ((C) ^ 0100) +struct MemoryView { + int64_t start; + unsigned zoom; +}; + struct MachineState { uint64_t ip; uint8_t cs[8]; @@ -204,6 +212,8 @@ struct Panels { }; }; +static const signed char kThePerfectKernel[8] = {-1, -3, 3, 17, 17, 3, -3, -1}; + static const char kRegisterNames[16][4] = { "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", @@ -215,6 +225,7 @@ static bool alarmed; static bool colorize; static bool mousemode; static bool printstats; +static bool showhighsse; static int tyn; static int txn; @@ -228,37 +239,32 @@ static int opline; static int action; static int xmmdisp; static int exitcode; -static int codezoom; -static int readzoom; -static int writezoom; -static int stackzoom; static long ips; static long rombase; static long codesize; static int64_t opstart; -static int64_t codestart; -static int64_t readstart; static int64_t mapsstart; -static int64_t writestart; -static int64_t stackstart; static int64_t framesstart; static int64_t breakpointsstart; static uint64_t last_opcount; static char *codepath; static void *onbusted; static char *statusmessage; -static struct Machine *m; static struct Pty *pty; +static struct Machine *m; static struct Panels pan; +static struct MemoryView codeview; +static struct MemoryView readview; +static struct MemoryView writeview; +static struct MemoryView stackview; static struct MachineState laststate; static struct Breakpoints breakpoints; static struct MachineMemstat lastmemstat; +static struct XmmType xmmtype; static struct Elf elf[1]; static struct Dis dis[1]; -static uint8_t xmmtype[16]; -static uint8_t xmmsize[16]; long double last_seconds; static long double statusexpires; @@ -308,9 +314,9 @@ static bool IsRet(void) { } static int GetXmmTypeCellCount(int r) { - switch (xmmtype[r]) { + switch (xmmtype.type[r]) { case kXmmIntegral: - return 16 / xmmsize[r]; + return 16 / xmmtype.size[r]; case kXmmFloat: return 4; case kXmmDouble: @@ -398,162 +404,6 @@ static int64_t ReadWord(uint8_t *p) { } } -static void UpdateXmmTypes(int regtype, int rmtype) { - xmmtype[RexrReg(m->xedd->op.rde)] = regtype; - if (IsModrmRegister(m->xedd->op.rde)) { - xmmtype[RexbRm(m->xedd->op.rde)] = rmtype; - } -} - -static void UpdateXmmSizes(int regsize, int rmsize) { - xmmsize[RexrReg(m->xedd->op.rde)] = regsize; - if (IsModrmRegister(m->xedd->op.rde)) { - xmmsize[RexbRm(m->xedd->op.rde)] = rmsize; - } -} - -static void UpdateXmmType(void) { - switch (m->xedd->op.dispatch) { - case 0x12E: // UCOMIS - case 0x12F: // COMIS - case 0x151: // SQRT - case 0x152: // RSQRT - case 0x153: // RCP - case 0x158: // ADD - case 0x159: // MUL - case 0x15C: // SUB - case 0x15D: // MIN - case 0x15E: // DIV - case 0x15F: // MAX - case 0x1C2: // CMP - if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { - UpdateXmmTypes(kXmmDouble, kXmmDouble); - } else { - UpdateXmmTypes(kXmmFloat, kXmmFloat); - } - break; - case 0x12A: // CVTPI2PS,CVTSI2SS,CVTPI2PD,CVTSI2SD - if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { - UpdateXmmSizes(8, 4); - UpdateXmmTypes(kXmmDouble, kXmmIntegral); - } else { - UpdateXmmSizes(4, 4); - UpdateXmmTypes(kXmmFloat, kXmmIntegral); - } - break; - case 0x15A: // CVT{P,S}{S,D}2{P,S}{S,D} - if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { - UpdateXmmTypes(kXmmFloat, kXmmDouble); - } else { - UpdateXmmTypes(kXmmDouble, kXmmFloat); - } - break; - case 0x15B: // CVT{,T}{DQ,PS}2{PS,DQ} - UpdateXmmSizes(4, 4); - if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 3) { - UpdateXmmTypes(kXmmIntegral, kXmmFloat); - } else { - UpdateXmmTypes(kXmmFloat, kXmmIntegral); - } - break; - case 0x17C: // HADD - case 0x17D: // HSUB - case 0x1D0: // ADDSUB - if (Osz(m->xedd->op.rde)) { - UpdateXmmTypes(kXmmDouble, kXmmDouble); - } else { - UpdateXmmTypes(kXmmFloat, kXmmFloat); - } - break; - case 0x164: // PCMPGTB - case 0x174: // PCMPEQB - case 0x1D8: // PSUBUSB - case 0x1DA: // PMINUB - case 0x1DC: // PADDUSB - case 0x1DE: // PMAXUB - case 0x1E0: // PAVGB - case 0x1E8: // PSUBSB - case 0x1EC: // PADDSB - case 0x1F8: // PSUBB - case 0x1FC: // PADDB - UpdateXmmSizes(1, 1); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x165: // PCMPGTW - case 0x175: // PCMPEQW - case 0x171: // PSRLW,PSRAW,PSLLW - case 0x1D1: // PSRLW - case 0x1D5: // PMULLW - case 0x1D9: // PSUBUSW - case 0x1DD: // PADDUSW - case 0x1E1: // PSRAW - case 0x1E3: // PAVGW - case 0x1E4: // PMULHUW - case 0x1E5: // PMULHW - case 0x1E9: // PSUBSW - case 0x1EA: // PMINSW - case 0x1ED: // PADDSW - case 0x1EE: // PMAXSW - case 0x1F1: // PSLLW - case 0x1F6: // PSADBW - case 0x1F9: // PSUBW - case 0x1FD: // PADDW - UpdateXmmSizes(2, 2); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x166: // PCMPGTD - case 0x176: // PCMPEQD - case 0x172: // PSRLD,PSRAD,PSLLD - case 0x1D2: // PSRLD - case 0x1E2: // PSRAD - case 0x1F2: // PSLLD - case 0x1FA: // PSUBD - case 0x1FE: // PADDD - UpdateXmmSizes(4, 4); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x173: // PSRLQ,PSRLQ,PSRLDQ,PSLLQ,PSLLDQ - case 0x1D3: // PSRLQ - case 0x1D4: // PADDQ - case 0x1F3: // PSLLQ - case 0x1F4: // PMULUDQ - case 0x1FB: // PSUBQ - UpdateXmmSizes(8, 8); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x16B: // PACKSSDW - case 0x1F5: // PMADDWD - UpdateXmmSizes(4, 2); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x163: // PACKSSWB - case 0x167: // PACKUSWB - UpdateXmmSizes(1, 2); - UpdateXmmTypes(kXmmIntegral, kXmmIntegral); - break; - case 0x128: // MOVAPS Vps Wps - if (IsModrmRegister(m->xedd->op.rde)) { - xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)]; - xmmsize[RexrReg(m->xedd->op.rde)] = xmmsize[RexbRm(m->xedd->op.rde)]; - } - break; - case 0x129: // MOVAPS Wps Vps - if (IsModrmRegister(m->xedd->op.rde)) { - xmmtype[RexbRm(m->xedd->op.rde)] = xmmtype[RexrReg(m->xedd->op.rde)]; - xmmsize[RexbRm(m->xedd->op.rde)] = xmmsize[RexrReg(m->xedd->op.rde)]; - } - break; - case 0x16F: // MOVDQA Vdq Wdq - if (Osz(m->xedd->op.rde) && IsModrmRegister(m->xedd->op.rde)) { - xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)]; - xmmsize[RexrReg(m->xedd->op.rde)] = xmmsize[RexbRm(m->xedd->op.rde)]; - } - break; - default: - return; - } -} - static void CopyMachineState(struct MachineState *ms) { ms->ip = m->ip; memcpy(ms->cs, m->cs, sizeof(m->cs)); @@ -861,12 +711,14 @@ static bool IsSegNonZero(void) { static int PickNumberOfXmmRegistersToShow(void) { if (IsXmmNonZero(0, 8) || IsXmmNonZero(8, 16)) { - if (IsXmmNonZero(8, 16)) { + if (showhighsse || IsXmmNonZero(8, 16)) { + showhighsse = true; return 16; } else { return 8; } } else { + showhighsse = false; return 0; } } @@ -1248,7 +1100,7 @@ static void DrawXmm(struct Panel *p, long i, long r) { cellwidth = MIN(MAX(0, (panwidth - left) / cells - 1), sizeof(buf) - 1); for (j = 0; j < cells; ++j) { AppendPanel(p, i, " "); - switch (xmmtype[r]) { + switch (xmmtype.type[r]) { case kXmmFloat: memcpy(&f, xmm + j * sizeof(f), sizeof(f)); FormatDouble(buf, f); @@ -1259,8 +1111,8 @@ static void DrawXmm(struct Panel *p, long i, long r) { break; case kXmmIntegral: ival = 0; - for (k = 0; k < xmmsize[r]; ++k) { - itmp = xmm[j * xmmsize[r] + k] & 0xff; + for (k = 0; k < xmmtype.size[r]; ++k) { + itmp = xmm[j * xmmtype.size[r] + k] & 0xff; itmp <<= k * 8; ival |= itmp; } @@ -1268,10 +1120,10 @@ static void DrawXmm(struct Panel *p, long i, long r) { if (xmmdisp == kXmmChar && iswalnum(ival)) { sprintf(buf, "%lc", ival); } else { - uint64toarray_fixed16(ival, buf, xmmsize[r] * 8); + uint64toarray_fixed16(ival, buf, xmmtype.size[r] * 8); } } else { - int64toarray_radix10(SignExtend(ival, xmmsize[r] * 8), buf); + int64toarray_radix10(SignExtend(ival, xmmtype.size[r] * 8), buf); } break; default: @@ -1288,91 +1140,125 @@ static void DrawXmm(struct Panel *p, long i, long r) { } static void DrawSse(struct Panel *p) { - long i; - if (p->top == p->bottom) return; - for (i = 0; i < MIN(16, MAX(0, p->bottom - p->top)); ++i) { - DrawXmm(p, i, i); - } -} - -static void ScrollCode(struct Panel *p) { long i, n; n = p->bottom - p->top; - i = GetIp() / DUMPWIDTH; - if (!(codestart <= i && i < codestart + n)) { - codestart = i; + if (n > 0) { + for (i = 0; i < MIN(16, n); ++i) { + DrawXmm(p, i, i); + } } } -static void ScrollReadData(struct Panel *p) { - long i, n, addr; - n = p->bottom - p->top; - i = m->readaddr / (DUMPWIDTH * (1 << readzoom)); - if (!(readstart <= i && i < readstart + n)) { - readstart = i - n / 3; - } -} - -static void ScrollWriteData(struct Panel *p) { - long i, n, addr; - n = p->bottom - p->top; - i = m->writeaddr / DUMPWIDTH; - if (!(writestart <= i && i < writestart + n)) { - writestart = i - n / 3; - } -} - -static void ScrollStack(struct Panel *p) { +static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, int64_t a) { long i, n; n = p->bottom - p->top; - i = GetSp() / DUMPWIDTH; - if (!(stackstart <= i && i < stackstart + n)) { - stackstart = i; + i = a / (DUMPWIDTH * (1ull << v->zoom)); + if (!(v->start <= i && i < v->start + n)) { + v->start = i; } } -static uint8_t Downsample(uint8_t al, uint8_t bl, uint8_t cl, uint8_t dl) { - int16_t ax, bx; - bx = bl; - bx += cl; - bx *= 3; - ax = al; - ax += dl; - ax += bx; - ax += 4; - ax >>= 3; - al = ax; - return al; +static void ZoomMemoryView(struct MemoryView *v, int dy) { + v->start *= (DUMPWIDTH * (1ull << v->zoom)); + v->zoom = MIN(MAXZOOM, MAX(0, v->zoom + dy)); + v->start /= (DUMPWIDTH * (1ull << v->zoom)); } -static uint8_t Sharpen(uint8_t al, uint8_t bl, uint8_t cl) { - int16_t ax, bx, cx; - ax = al; - bx = bl; - cx = cl; - ax *= -1; - bx *= +6; - cx *= -1; - ax += bx; - ax += cx; - ax += 2; - ax >>= 2; - return MIN(255, MAX(0, ax)); +static void ScrollMemoryViews(void) { + ScrollMemoryView(&pan.code, &codeview, GetIp()); + ScrollMemoryView(&pan.readdata, &readview, m->readaddr); + ScrollMemoryView(&pan.writedata, &writeview, m->writeaddr); + ScrollMemoryView(&pan.stack, &stackview, GetSp()); } -static void DrawMemory(struct Panel *p, int zoom, long startline, long histart, - long hiend) { - char buf[16]; +static void ZoomMemoryViews(struct Panel *p, int dy) { + if (p == &pan.code) { + ZoomMemoryView(&codeview, dy); + } else if (p == &pan.readdata) { + ZoomMemoryView(&readview, dy); + } else if (p == &pan.writedata) { + ZoomMemoryView(&writeview, dy); + } else if (p == &pan.stack) { + ZoomMemoryView(&stackview, dy); + } +} + +static void DrawMemoryZoomed(struct Panel *p, struct MemoryView *view, + long histart, long hiend) { + bool high, changed; + uint8_t *canvas, *chunk, *invalid; + int64_t a, b, c, d, n, i, j, k, size; + struct ContiguousMemoryRanges ranges; + a = view->start * DUMPWIDTH * (1ull << view->zoom); + b = (view->start + (p->bottom - p->top)) * DUMPWIDTH * (1ull << view->zoom); + size = (p->bottom - p->top) * DUMPWIDTH; + canvas = xcalloc(1, size); + invalid = xcalloc(1, size); + memset(&ranges, 0, sizeof(ranges)); + FindContiguousMemoryRanges(m, &ranges); + for (k = i = 0; i < ranges.i; ++i) { + if ((a >= ranges.p[i].a && a < ranges.p[i].b) || + (b >= ranges.p[i].a && b < ranges.p[i].b) || + (a < ranges.p[i].a && b >= ranges.p[i].b)) { + c = MAX(a, ranges.p[i].a); + d = MIN(b, ranges.p[i].b); + n = ROUNDUP(ROUNDUP(d - c, 16), 1ull << view->zoom); + chunk = xmalloc(n); + VirtualSend(m, chunk, c, d - c); + memset(chunk + (d - c), 0, n - (d - c)); + for (j = 0; j < view->zoom; ++j) { + cDecimate2xUint8x8(ROUNDUP(n, 16), chunk, kThePerfectKernel); + n >>= 1; + } + j = (c - a) / (1ull << view->zoom); + memset(invalid + k, -1, j - k); + memcpy(canvas + j, chunk, MIN(n, size - j)); + k = j + MIN(n, size - j); + free(chunk); + } + } + memset(invalid + k, -1, size - k); + free(ranges.p); + high = false; + for (c = i = 0; i < p->bottom - p->top; ++i) { + AppendFmt(&p->lines[i], "%p ", + (view->start + i) * DUMPWIDTH * (1ull << view->zoom)); + for (j = 0; j < DUMPWIDTH; ++j, ++c) { + a = ((view->start + i) * DUMPWIDTH + j + 0) * (1ull << view->zoom); + b = ((view->start + i) * DUMPWIDTH + j + 1) * (1ull << view->zoom); + changed = ((histart >= a && hiend < b) || + (histart && hiend && histart >= a && hiend < b)); + if (changed && !high) { + high = true; + AppendStr(&p->lines[i], "\e[7m"); + } else if (!changed && high) { + AppendStr(&p->lines[i], "\e[27m"); + high = false; + } + if (invalid[c]) { + AppendWide(&p->lines[i], u'⋅'); + } else { + AppendWide(&p->lines[i], kCp437[canvas[c]]); + } + } + if (high) { + AppendStr(&p->lines[i], "\e[27m"); + high = false; + } + } + free(invalid); + free(canvas); +} + +static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, + long histart, long hiend) { + long i, j, k, c; bool high, changed; - long i, j, k, c, width; - if (p->top == p->bottom) return; high = false; - width = DUMPWIDTH * (1 << zoom); for (i = 0; i < p->bottom - p->top; ++i) { - snprintf(buf, sizeof(buf), "%p ", (startline + i) * width); - AppendStr(&p->lines[i], buf); - for (j = 0; j < width; ++j) { - k = (startline + i) * DUMPWIDTH + j; + AppendFmt(&p->lines[i], "%p ", (view->start + i) * DUMPWIDTH); + for (j = 0; j < DUMPWIDTH; ++j) { + k = (view->start + i) * DUMPWIDTH + j; c = VirtualBing(k); changed = histart <= k && k < hiend; if (changed && !high) { @@ -1391,6 +1277,16 @@ static void DrawMemory(struct Panel *p, int zoom, long startline, long histart, } } +static void DrawMemory(struct Panel *p, struct MemoryView *view, long histart, + long hiend) { + if (p->top == p->bottom) return; + if (view->zoom) { + DrawMemoryZoomed(p, view, histart, hiend); + } else { + DrawMemoryUnzoomed(p, view, histart, hiend); + } +} + static void DrawMaps(struct Panel *p) { int i; char *text, *p1, *p2; @@ -1597,14 +1493,11 @@ static void Redraw(void) { DrawMaps(&pan.maps); DrawFrames(&pan.frames); DrawBreakpoints(&pan.breakpoints); - DrawMemory(&pan.code, codezoom, codestart, GetIp(), - GetIp() + m->xedd->length); - DrawMemory(&pan.readdata, readzoom, readstart, m->readaddr, - m->readaddr + m->readsize); - DrawMemory(&pan.writedata, writezoom, writestart, m->writeaddr, + DrawMemory(&pan.code, &codeview, GetIp(), GetIp() + m->xedd->length); + DrawMemory(&pan.readdata, &readview, m->readaddr, m->readaddr + m->readsize); + DrawMemory(&pan.writedata, &writeview, m->writeaddr, m->writeaddr + m->writesize); - DrawMemory(&pan.stack, stackzoom, stackstart, GetSp(), - GetSp() + GetPointerWidth()); + DrawMemory(&pan.stack, &stackview, GetSp(), GetSp() + GetPointerWidth()); DrawStatus(&pan.status); PreventBufferbloat(); if (PrintPanels(ttyout, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) { @@ -2295,16 +2188,16 @@ static void OnRestart(void) { static void OnXmmType(void) { uint8_t t; unsigned i; - t = CycleXmmType(xmmtype[0]); + t = CycleXmmType(xmmtype.type[0]); for (i = 0; i < 16; ++i) { - xmmtype[i] = t; + xmmtype.type[i] = t; } } static void SetXmmSize(int bytes) { unsigned i; for (i = 0; i < 16; ++i) { - xmmsize[i] = bytes; + xmmtype.size[i] = bytes; } } @@ -2313,7 +2206,7 @@ static void SetXmmDisp(int disp) { } static void OnXmmSize(void) { - SetXmmSize(CycleXmmSize(xmmsize[0])); + SetXmmSize(CycleXmmSize(xmmtype.size[0])); } static void OnXmmDisp(void) { @@ -2328,8 +2221,67 @@ static void Sleep(int ms) { poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms); } +static void OnMouseWheelUp(struct Panel *p) { + if (p == &pan.disassembly) { + opstart -= WHEELDELTA; + } else if (p == &pan.code) { + codeview.start -= WHEELDELTA; + } else if (p == &pan.readdata) { + readview.start -= WHEELDELTA; + } else if (p == &pan.writedata) { + writeview.start -= WHEELDELTA; + } else if (p == &pan.stack) { + stackview.start -= WHEELDELTA; + } else if (p == &pan.maps) { + mapsstart = MAX(0, mapsstart - 1); + } else if (p == &pan.frames) { + framesstart = MAX(0, framesstart - 1); + } else if (p == &pan.breakpoints) { + breakpointsstart = MAX(0, breakpointsstart - 1); + } +} + +static void OnMouseWheelDown(struct Panel *p) { + if (p == &pan.disassembly) { + opstart += WHEELDELTA; + } else if (p == &pan.code) { + codeview.start += WHEELDELTA; + } else if (p == &pan.readdata) { + readview.start += WHEELDELTA; + } else if (p == &pan.writedata) { + writeview.start += WHEELDELTA; + } else if (p == &pan.stack) { + stackview.start += WHEELDELTA; + } else if (p == &pan.maps) { + mapsstart += 1; + } else if (p == &pan.frames) { + framesstart += 1; + } else if (p == &pan.breakpoints) { + breakpointsstart += 1; + } +} + +static void OnMouseCtrlWheelUp(struct Panel *p) { + ZoomMemoryViews(p, -1); +} + +static void OnMouseCtrlWheelDown(struct Panel *p) { + ZoomMemoryViews(p, +1); +} + +static struct Panel *LocatePanel(int y, int x) { + int i; + for (i = 0; i < ARRAYLEN(pan.p); ++i) { + if ((pan.p[i].left <= x && x < pan.p[i].right) && + (pan.p[i].top <= y && y < pan.p[i].bottom)) { + return &pan.p[i]; + } + } + return NULL; +} + static void OnMouse(char *p) { - int e, i, x, y, dy; + int e, x, y; struct Panel *ep; e = strtol(p, &p, 10); if (*p == ';') ++p; @@ -2337,37 +2289,19 @@ static void OnMouse(char *p) { if (*p == ';') ++p; y = min(tyn, max(1, strtol(p, &p, 10))) - 1; e |= (*p == 'm') << 2; - for (ep = 0, i = 0; i < ARRAYLEN(pan.p); ++i) { - if ((pan.p[i].left <= x && x < pan.p[i].right) && - (pan.p[i].top <= y && y < pan.p[i].bottom)) { - ep = &pan.p[i]; - break; - } - } - if (ep) { - dy = 3; + if ((ep = LocatePanel(y, x))) { switch (e) { case kMouseWheelUp: - if (ep == &pan.disassembly) opstart -= dy; - if (ep == &pan.code) codestart -= dy; - if (ep == &pan.readdata) readstart -= dy; - if (ep == &pan.writedata) writestart -= dy; - if (ep == &pan.stack) stackstart -= dy; - if (ep == &pan.maps) mapsstart = MAX(0, mapsstart - 1); - if (ep == &pan.frames) framesstart = MAX(0, framesstart - 1); - if (ep == &pan.breakpoints) { - breakpointsstart = MAX(0, breakpointsstart - 1); - } + OnMouseWheelUp(ep); break; case kMouseWheelDown: - if (ep == &pan.disassembly) opstart += dy; - if (ep == &pan.code) codestart += dy; - if (ep == &pan.readdata) readstart += dy; - if (ep == &pan.writedata) writestart += dy; - if (ep == &pan.stack) stackstart += dy; - if (ep == &pan.maps) mapsstart += 1; - if (ep == &pan.frames) framesstart += 1; - if (ep == &pan.breakpoints) breakpointsstart += 1; + OnMouseWheelDown(ep); + break; + case kMouseCtrlWheelUp: + OnMouseCtrlWheelUp(ep); + break; + case kMouseCtrlWheelDown: + OnMouseCtrlWheelDown(ep); break; default: break; @@ -2377,6 +2311,7 @@ static void OnMouse(char *p) { static void ReadKeyboard(void) { char buf[64], *p = buf; + memset(buf, 0, sizeof(buf)); if (readansi(ttyin, buf, sizeof(buf)) == -1) { if (errno == EINTR) { LOGF("readkeyboard interrupted"); @@ -2573,7 +2508,6 @@ static void Tui(void) { for (;;) { if (!(action & FAILURE)) { LoadInstruction(m); - UpdateXmmType(); if ((action & (FINISH | NEXT | CONTINUE)) && (bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { action &= ~(FINISH | NEXT | CONTINUE); @@ -2598,10 +2532,7 @@ static void Tui(void) { HandleAlarm(); } if (action & FAILURE) { - ScrollCode(&pan.code); - ScrollStack(&pan.stack); - ScrollReadData(&pan.readdata); - ScrollWriteData(&pan.writedata); + ScrollMemoryViews(); } if (!(action & CONTINUE) || interactive) { tick = 0; @@ -2666,13 +2597,11 @@ static void Tui(void) { } } if (!IsDebugBreak()) { + UpdateXmmType(m, &xmmtype); ExecuteInstruction(m); ++opcount; if (!(action & CONTINUE) || interactive) { - ScrollCode(&pan.code); - ScrollStack(&pan.stack); - ScrollReadData(&pan.readdata); - ScrollWriteData(&pan.writedata); + ScrollMemoryViews(); } } else { m->ip += m->xedd->length; @@ -2703,7 +2632,7 @@ static void Tui(void) { static void GetOpts(int argc, char *argv[]) { int opt; stpcpy(stpcpy(stpcpy(logpath, kTmpPath), basename(argv[0])), ".log"); - while ((opt = getopt(argc, argv, "hvtrRsb:HL:")) != -1) { + while ((opt = getopt(argc, argv, "hvtrzRsb:HL:")) != -1) { switch (opt) { case 't': tuimode = true; @@ -2730,6 +2659,12 @@ static void GetOpts(int argc, char *argv[]) { case 'L': strcpy(logpath, optarg); break; + case 'z': + ++codeview.zoom; + ++readview.zoom; + ++writeview.zoom; + ++stackview.zoom; + break; case 'h': PrintUsage(EXIT_SUCCESS, stdout); default: diff --git a/tool/build/emubin/lisp.h b/tool/build/emubin/lisp.h deleted file mode 100644 index e97e983e..00000000 --- a/tool/build/emubin/lisp.h +++ /dev/null @@ -1,180 +0,0 @@ -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ The LISP Challenge § Hardware Integration w/ x86_64 Linux & 8086 PC BIOS ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#define CompilerBarrier() asm volatile("" ::: "memory"); - -#define ISATOM(x) /* a.k.a. !(x&1) */ \ - ({ \ - _Bool IsAtom; \ - asm("test%z1\t$1,%1" : "=@ccz"(IsAtom) : "Qm"((char)x)); \ - IsAtom; \ - }) - -#define OBJECT(t, v) /* a.k.a. v<<1|t */ \ - ({ \ - __typeof(v) Val = (v); \ - asm("shl\t%0" : "+r"(Val)); \ - Val | (t); \ - }) - -#define SUB(x, y) /* a.k.a. x-y */ \ - ({ \ - __typeof(x) Reg = (x); \ - asm("sub\t%1,%0" : "+rm"(Reg) : "g"(y)); \ - Reg; \ - }) - -#define STOS(di, c) asm("stos%z1" : "+D"(di), "=m"(*(di)) : "a"(c)) -#define LODS(si) \ - ({ \ - typeof(*(si)) c; \ - asm("lods%z2" : "+S"(si), "=a"(c) : "m"(*(si))); \ - c; \ - }) - -#define PEEK_(REG, BASE, INDEX, DISP) \ - ({ \ - __typeof(*(BASE)) Reg; \ - if (__builtin_constant_p(INDEX) && !(INDEX)) { \ - asm("mov\t%c2(%1),%0" \ - : REG(Reg) \ - : "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \ - "m"(BASE[(INDEX) + (DISP)])); \ - } else { \ - asm("mov\t%c3(%1,%2),%0" \ - : REG(Reg) \ - : "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \ - "i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \ - } \ - Reg; \ - }) - -#define PEEK(BASE, INDEX, DISP) /* a.k.a. b[i] */ \ - (sizeof(*(BASE)) == 1 ? PEEK_("=Q", BASE, INDEX, DISP) \ - : PEEK_("=r", BASE, INDEX, DISP)) - -#define PEEK_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP) \ - ({ \ - __typeof(*(OBJECT->MEMBER)) Reg; \ - if (!(OBJECT)) { \ - asm("mov\t%c2(%1),%0" \ - : REG(Reg) \ - : "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \ - "i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \ - sizeof(*(OBJECT->MEMBER)) * (DISP)), \ - "m"(OBJECT->MEMBER)); \ - } else { \ - asm("mov\t%c3(%1,%2),%0" \ - : REG(Reg) \ - : "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \ - "i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \ - sizeof(*(OBJECT->MEMBER)) * (DISP)), \ - "m"(OBJECT->MEMBER)); \ - } \ - Reg; \ - }) - -#define PEEK_ARRAY(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \ - (sizeof(*(OBJECT->MEMBER)) == 1 \ - ? PEEK_ARRAY_("=Q", OBJECT, MEMBER, INDEX, DISP) \ - : PEEK_ARRAY_("=r", OBJECT, MEMBER, INDEX, DISP)) - -#define POKE_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \ - do { \ - if (!(OBJECT)) { \ - asm("mov\t%1,%c3(%2)" \ - : "=m"(OBJECT->MEMBER) \ - : REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \ - "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \ - "i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \ - sizeof(*(OBJECT->MEMBER)) * (DISP))); \ - } else { \ - asm("mov\t%1,%c4(%2,%3)" \ - : "=m"(OBJECT->MEMBER) \ - : REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \ - "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \ - "i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \ - sizeof(*(OBJECT->MEMBER)) * (DISP))); \ - } \ - } while (0) - -#define POKE_ARRAY(OBJECT, MEMBER, INDEX, DISP, VALUE) /* o->m[i]=v */ \ - do { \ - __typeof(*(OBJECT->MEMBER)) Reg; \ - switch (sizeof(*(OBJECT->MEMBER))) { \ - case 1: \ - POKE_ARRAY_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \ - break; \ - default: \ - POKE_ARRAY_("r", OBJECT, MEMBER, INDEX, DISP, VALUE); \ - break; \ - } \ - } while (0) - -static inline void *SetMemory(void *di, int al, unsigned long cx) { - asm("rep stosb" - : "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di) - : "0"(di), "1"(cx), "a"(al)); - return di; -} - -static inline void *CopyMemory(void *di, void *si, unsigned long cx) { - asm("rep movsb" - : "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di) - : "0"(di), "1"(si), "2"(cx)); - return di; -} - -static void RawMode(void) { -#ifndef __REAL_MODE__ - int rc; - int c[14]; - asm volatile("syscall" - : "=a"(rc) - : "0"(0x10), "D"(0), "S"(0x5401), "d"(c) - : "rcx", "r11", "memory"); - c[0] &= ~0b0000010111111000; // INPCK|ISTRIP|PARMRK|INLCR|IGNCR|ICRNL|IXON - c[2] &= ~0b0000000100110000; // CSIZE|PARENB - c[2] |= 0b00000000000110000; // CS8 - c[3] &= ~0b1000000001011010; // ECHONL|ECHO|ECHOE|IEXTEN|ICANON - asm volatile("syscall" - : "=a"(rc) - : "0"(0x10), "D"(0), "S"(0x5402), "d"(c) - : "rcx", "r11", "memory"); -#endif -} - -__attribute__((__noinline__)) static void PrintChar(long c) { -#ifdef __REAL_MODE__ - asm volatile("mov\t$0x0E,%%ah\n\t" - "int\t$0x10" - : /* no outputs */ - : "a"(c), "b"(7) - : "memory"); -#else - static short buf; - int rc; - buf = c; - asm volatile("syscall" - : "=a"(rc) - : "0"(1), "D"(1), "S"(&buf), "d"(1) - : "rcx", "r11", "memory"); -#endif -} - -static int ReadChar(void) { - int c; -#ifdef __REAL_MODE__ - asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory"); - c &= 0xff; -#else - static int buf; - asm volatile("syscall" - : "=a"(c) - : "0"(0), "D"(0), "S"(&buf), "d"(1) - : "rcx", "r11", "memory"); - c = buf; -#endif - return c; -} diff --git a/tool/build/emubin/lisp.lisp b/tool/build/emubin/lisp.lisp deleted file mode 100644 index d1836107..00000000 --- a/tool/build/emubin/lisp.lisp +++ /dev/null @@ -1,105 +0,0 @@ -;; (setq lisp-indent-function 'common-lisp-indent-function) -;; (paredit-mode) - -;; ________ -;; /_ __/ /_ ___ -;; / / / __ \/ _ \ -;; / / / / / / __/ -;; /_/ /_/ /_/\___/ -;; __ _________ ____ ________ ____ -;; / / / _/ ___// __ \ / ____/ /_ ____ _/ / /__ ____ ____ ____ -;; / / / / \__ \/ /_/ / / / / __ \/ __ `/ / / _ \/ __ \/ __ `/ _ \ -;; / /____/ / ___/ / ____/ / /___/ / / / /_/ / / / __/ / / / /_/ / __/ -;; /_____/___//____/_/ \____/_/ /_/\__,_/_/_/\___/_/ /_/\__, /\___/ -;; /____/ -;; -;; THE LISP CHALLENGE -;; -;; PICK YOUR FAVORITE PROGRAMMING LANGUAGE -;; IMPLEMENT THE TINIEST POSSIBLE LISP MACHINE THAT -;; BOOTSTRAPS JOHN MCCARTHY'S METACIRCULAR EVALUATOR -;; WINNING IS DEFINED BY LINES OF CODE FOR SCRIPTING LANGUAGES -;; WINNING IS DEFINED BY BINARY FOOTPRINT FOR COMPILED LANGUAGES -;; -;; @SEE LISP FROM NOTHING; NILS M. HOLM; LULU PRESS, INC. 2020 -;; @SEE RECURSIVE FUNCTIONS OF SYMBOLIC EXPRESSIONS AND THEIR -;; COMPUTATION BY MACHINE, PART I; JOHN MCCARTHY, MASSACHUSETTS -;; INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASS. APRIL 1960 - -;; NIL ATOM -;; ABSENCE OF VALUE -NIL - -;; CONS CELL -;; BUILDING BLOCK OF DATA STRUCTURES -(CONS NIL NIL) - -;; REFLECTION -;; EVERYTHING IS AN ATOM OR NOT AN ATOM -(ATOM NIL) -(ATOM (CONS NIL NIL)) - -;; QUOTING -;; CODE IS DATA AND DATA IS CODE -(QUOTE (CONS NIL NIL)) -(CONS (QUOTE CONS) (CONS NIL (CONS NIL NIL))) - -;; LOGIC -;; LAW OF IDENTITY VIA STRING INTERNING -(EQ (QUOTE A) (QUOTE A)) - -;; FIND FIRST ATOM IN TREE -;; RECURSIVE CONDITIONAL FUNCTION BINDING -((LAMBDA (FF X) (FF X)) - (QUOTE (LAMBDA (X) - (COND ((ATOM X) X) - ((QUOTE T) (FF (CAR X)))))) - (QUOTE ((A) B C))) - -;; LISP IMPLEMENTED IN LISP -;; USED TO EVALUATE FIND FIRST ATOM IN TREE -;; REQUIRES CONS CAR CDR QUOTE ATOM EQ LAMBDA COND -;; FIXES BUGS FROM JOHN MCCARTHY PAPER AND MORE MINIMAL -((LAMBDA (ASSOC EVCON BIND APPEND EVAL) - (EVAL (QUOTE ((LAMBDA (FF X) (FF X)) - (QUOTE (LAMBDA (X) - (COND ((ATOM X) X) - ((QUOTE T) (FF (CAR X)))))) - (QUOTE ((A) B C)))) - NIL)) - (QUOTE (LAMBDA (X E) - (COND ((EQ E NIL) NIL) - ((EQ X (CAR (CAR E))) (CDR (CAR E))) - ((QUOTE T) (ASSOC X (CDR E)))))) - (QUOTE (LAMBDA (C E) - (COND ((EVAL (CAR (CAR C)) E) (EVAL (CAR (CDR (CAR C))) E)) - ((QUOTE T) (EVCON (CDR C) E))))) - (QUOTE (LAMBDA (V A E) - (COND ((EQ V NIL) E) - ((QUOTE T) (CONS (CONS (CAR V) (EVAL (CAR A) E)) - (BIND (CDR V) (CDR A) E)))))) - (QUOTE (LAMBDA (A B) - (COND ((EQ A NIL) B) - ((QUOTE T) (CONS (CAR A) (APPEND (CDR A) B)))))) - (QUOTE (LAMBDA (E A) - (COND - ((ATOM E) (ASSOC E A)) - ((ATOM (CAR E)) - (COND - ((EQ (CAR E) NIL) (QUOTE *UNDEFINED)) - ((EQ (CAR E) (QUOTE QUOTE)) (CAR (CDR E))) - ((EQ (CAR E) (QUOTE ATOM)) (ATOM (EVAL (CAR (CDR E)) A))) - ((EQ (CAR E) (QUOTE EQ)) (EQ (EVAL (CAR (CDR E)) A) - (EVAL (CAR (CDR (CDR E))) A))) - ((EQ (CAR E) (QUOTE CAR)) (CAR (EVAL (CAR (CDR E)) A))) - ((EQ (CAR E) (QUOTE CDR)) (CDR (EVAL (CAR (CDR E)) A))) - ((EQ (CAR E) (QUOTE CONS)) (CONS (EVAL (CAR (CDR E)) A) - (EVAL (CAR (CDR (CDR E))) A))) - ((EQ (CAR E) (QUOTE COND)) (EVCON (CDR E) A)) - ((EQ (CAR E) (QUOTE LABEL)) (EVAL (CAR (CDR (CDR E))) - (APPEND (CAR (CDR E)) A))) - ((EQ (CAR E) (QUOTE LAMBDA)) E) - ((QUOTE T) (EVAL (CONS (EVAL (CAR E) A) (CDR E)) A)))) - ((EQ (CAR (CAR E)) (QUOTE LAMBDA)) - (EVAL (CAR (CDR (CDR (CAR E)))) - (BIND (CAR (CDR (CAR E))) (CDR E) A))))))) diff --git a/tool/build/emubin/lispelf.S b/tool/build/emubin/lispelf.S deleted file mode 100644 index 348211f7..00000000 --- a/tool/build/emubin/lispelf.S +++ /dev/null @@ -1,23 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.h" - -_start: jmp main - .endfn _start,globl diff --git a/tool/build/emubin/lispstart.S b/tool/build/emubin/lispstart.S deleted file mode 100644 index dd32a494..00000000 --- a/tool/build/emubin/lispstart.S +++ /dev/null @@ -1,51 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -.code16 -.section .start,"ax",@progbits - -_start: jmp 1f -1: ljmp $0x600>>4,$_begin - .type _start,@function - .size _start,.-_start - .globl _start - -_begin: push %cs - pop %ds - push %cs - pop %es - mov $0x70000>>4,%ax - cli - mov %ax,%ss - xor %sp,%sp - sti - cld - xor %ax,%ax - xor %di,%di - mov $0x7c00-0x600,%cx - rep stosb - xchg %di,%bx - inc %cx - xor %dh,%dh - mov $v_sectors+0x0200,%ax - int $0x13 - xor %bp,%bp - jmp main - .type _begin,@function - .size _begin,.-_begin diff --git a/tool/build/lib/buffer.c b/tool/build/lib/buffer.c index 3f58e9a9..900404a3 100644 --- a/tool/build/lib/buffer.c +++ b/tool/build/lib/buffer.c @@ -49,13 +49,16 @@ void AppendStr(struct Buffer *b, const char *s) { } void AppendWide(struct Buffer *b, wint_t wc) { + unsigned i; uint64_t wb; - wb = wc; - if (!isascii(wb)) wb = tpenc(wb); + char buf[8]; + i = 0; + wb = tpenc(wc); do { - AppendChar(b, wb & 0xFF); + buf[i++] = wb & 0xFF; wb >>= 8; } while (wb); + AppendData(b, buf, i); } int AppendFmt(struct Buffer *b, const char *fmt, ...) { @@ -72,24 +75,31 @@ int AppendFmt(struct Buffer *b, const char *fmt, ...) { } /** - * Writes buffer until completion, interrupt, or error occurs. + * Writes buffer until completion, or error occurs. */ ssize_t WriteBuffer(struct Buffer *b, int fd) { + bool t; char *p; ssize_t rc; size_t wrote, n; p = b->p; n = b->i; + t = false; do { if ((rc = write(fd, p, n)) != -1) { wrote = rc; p += wrote; n -= wrote; } else if (errno == EINTR) { - break; + t = true; } else { return -1; } } while (n); - return 0; + if (!t) { + return 0; + } else { + errno = EINTR; + return -1; + } } diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index 611747c1..34bb726b 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -28,6 +28,7 @@ #include "libc/runtime/runtime.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/mremap.h" +#include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/ok.h" #include "libc/sysv/consts/prot.h" @@ -177,6 +178,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode) { void elfwriter_close(struct ElfWriter *elf) { size_t i; FlushTables(elf); + CHECK_NE(-1, msync(elf->map, elf->wrote, MS_SYNC)); CHECK_NE(-1, munmap(elf->map, elf->mapsize)); CHECK_NE(-1, ftruncate(elf->fd, elf->wrote)); CHECK_NE(-1, close(elf->fd)); diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index 24e79036..108bdd81 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -1632,6 +1632,7 @@ static void OpMovRqCq(struct Machine *m, uint32_t rde) { } static void OpMovCqRq(struct Machine *m, uint32_t rde) { + int64_t cr3; switch (ModrmReg(rde)) { case 0: m->cr0 = Read64(RegRexbRm(m, rde)); @@ -1640,7 +1641,12 @@ static void OpMovCqRq(struct Machine *m, uint32_t rde) { m->cr2 = Read64(RegRexbRm(m, rde)); break; case 3: - m->cr3 = Read64(RegRexbRm(m, rde)); + cr3 = Read64(RegRexbRm(m, rde)); + if (0 <= cr3 && cr3 + 512 * 8 <= m->real.n) { + m->cr3 = cr3; + } else { + ThrowProtectionFault(m); + } break; case 4: m->cr4 = Read64(RegRexbRm(m, rde)); diff --git a/tool/build/emubin/lisp.lds b/tool/build/lib/pml4t.c similarity index 51% rename from tool/build/emubin/lisp.lds rename to tool/build/lib/pml4t.c index 0a9f976e..d7378638 100644 --- a/tool/build/emubin/lisp.lds +++ b/tool/build/lib/pml4t.c @@ -1,5 +1,5 @@ -/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ -│vi: set et sts=2 tw=2 fenc=utf-8 :vi│ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ @@ -17,39 +17,47 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/arraylist2.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/machine.h" +#include "tool/build/lib/pml4t.h" -ENTRY(_start) +static void AppendContiguousMemoryRange(struct ContiguousMemoryRanges *ranges, + int64_t a, int64_t b) { + APPEND(&ranges->p, &ranges->i, &ranges->n, + (&(struct ContiguousMemoryRange){a, b})); +} -SECTIONS { - - .text 0x7c00 - 0x600 : { - *(.start .start.*) - rodata = .; - *(.rodata .rodata.*) - . = 0x1fe; - SHORT(0xaa55); - *(.text .text.*) - /*BYTE(0x90);*/ - _etext = .; - . = ALIGN(512); - } - - .bss : { - bss = .; - *(.bss .bss.*) - *(COMMON) - } - - /DISCARD/ : { - *(.*) +static void FindContiguousMemoryRangesImpl( + struct Machine *m, struct ContiguousMemoryRanges *ranges, int64_t addr, + unsigned level, int64_t pt, int64_t a, int64_t b) { + int64_t i, page, entry; + for (i = a; i < b; ++i) { + entry = Read64(m->real.p + pt + i * 8); + if (!(entry & 1)) continue; + entry &= 0x7ffffffff000; + page = (addr | i << level) << 16 >> 16; + if (level == 12) { + if (ranges->i && page == ranges->p[ranges->i - 1].b) { + ranges->p[ranges->i - 1].b += 0x1000; + } else { + AppendContiguousMemoryRange(ranges, page, page + 0x1000); + } + } else if (entry + 512 * 8 <= m->real.n) { + FindContiguousMemoryRangesImpl(m, ranges, page, level - 9, entry, 0, 512); + } } } -boot = 0x7c00; -q.syntax = 8192*2; -q.look = 8192*2+256; -q.globals = 8192*2+256+2; -q.index = 8192*2+256+2+2; -q.token = 8192*2+256+2+2+2; -q.str = 8192*2+256+2+2+2+128; -v_sectors = SIZEOF(.text) / 512; +void FindContiguousMemoryRanges(struct Machine *m, + struct ContiguousMemoryRanges *ranges) { + uint64_t cr3; + ranges->i = 0; + if ((m->mode & 3) == XED_MODE_LONG) { + cr3 = m->cr3 & 0x7ffffffff000; + FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 256, 512); + FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 0, 256); + } else { + AppendContiguousMemoryRange(ranges, 0, m->real.n); + } +} diff --git a/tool/build/lib/pml4t.h b/tool/build/lib/pml4t.h index 919341d1..4c23a5cd 100644 --- a/tool/build/lib/pml4t.h +++ b/tool/build/lib/pml4t.h @@ -8,6 +8,17 @@ COSMOPOLITAN_C_START_ #define UnmaskPageAddr(x) SignExtendAddr(MaskPageAddr(x)) #define SignExtendAddr(x) ((int64_t)((uint64_t)(x) << 16) >> 16) +struct ContiguousMemoryRanges { + size_t i, n; + struct ContiguousMemoryRange { + int64_t a; + int64_t b; + } * p; +}; + +void FindContiguousMemoryRanges(struct Machine *, + struct ContiguousMemoryRanges *); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_ */ diff --git a/tool/build/lib/xmmtype.c b/tool/build/lib/xmmtype.c new file mode 100644 index 00000000..4c64d206 --- /dev/null +++ b/tool/build/lib/xmmtype.c @@ -0,0 +1,179 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/modrm.h" +#include "tool/build/lib/xmmtype.h" + +static void UpdateXmmTypes(struct Machine *m, struct XmmType *xt, int regtype, + int rmtype) { + xt->type[RexrReg(m->xedd->op.rde)] = regtype; + if (IsModrmRegister(m->xedd->op.rde)) { + xt->type[RexbRm(m->xedd->op.rde)] = rmtype; + } +} + +static void UpdateXmmSizes(struct Machine *m, struct XmmType *xt, int regsize, + int rmsize) { + xt->size[RexrReg(m->xedd->op.rde)] = regsize; + if (IsModrmRegister(m->xedd->op.rde)) { + xt->size[RexbRm(m->xedd->op.rde)] = rmsize; + } +} + +void UpdateXmmType(struct Machine *m, struct XmmType *xt) { + switch (m->xedd->op.dispatch) { + case 0x12E: // UCOMIS + case 0x12F: // COMIS + case 0x151: // SQRT + case 0x152: // RSQRT + case 0x153: // RCP + case 0x158: // ADD + case 0x159: // MUL + case 0x15C: // SUB + case 0x15D: // MIN + case 0x15E: // DIV + case 0x15F: // MAX + case 0x1C2: // CMP + if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { + UpdateXmmTypes(m, xt, kXmmDouble, kXmmDouble); + } else { + UpdateXmmTypes(m, xt, kXmmFloat, kXmmFloat); + } + break; + case 0x12A: // CVTPI2PS,CVTSI2SS,CVTPI2PD,CVTSI2SD + if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { + UpdateXmmSizes(m, xt, 8, 4); + UpdateXmmTypes(m, xt, kXmmDouble, kXmmIntegral); + } else { + UpdateXmmSizes(m, xt, 4, 4); + UpdateXmmTypes(m, xt, kXmmFloat, kXmmIntegral); + } + break; + case 0x15A: // CVT{P,S}{S,D}2{P,S}{S,D} + if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 2) { + UpdateXmmTypes(m, xt, kXmmFloat, kXmmDouble); + } else { + UpdateXmmTypes(m, xt, kXmmDouble, kXmmFloat); + } + break; + case 0x15B: // CVT{,T}{DQ,PS}2{PS,DQ} + UpdateXmmSizes(m, xt, 4, 4); + if (Osz(m->xedd->op.rde) || Rep(m->xedd->op.rde) == 3) { + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmFloat); + } else { + UpdateXmmTypes(m, xt, kXmmFloat, kXmmIntegral); + } + break; + case 0x17C: // HADD + case 0x17D: // HSUB + case 0x1D0: // ADDSUB + if (Osz(m->xedd->op.rde)) { + UpdateXmmTypes(m, xt, kXmmDouble, kXmmDouble); + } else { + UpdateXmmTypes(m, xt, kXmmFloat, kXmmFloat); + } + break; + case 0x164: // PCMPGTB + case 0x174: // PCMPEQB + case 0x1D8: // PSUBUSB + case 0x1DA: // PMINUB + case 0x1DC: // PADDUSB + case 0x1DE: // PMAXUB + case 0x1E0: // PAVGB + case 0x1E8: // PSUBSB + case 0x1EC: // PADDSB + case 0x1F8: // PSUBB + case 0x1FC: // PADDB + UpdateXmmSizes(m, xt, 1, 1); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x165: // PCMPGTW + case 0x175: // PCMPEQW + case 0x171: // PSRLW,PSRAW,PSLLW + case 0x1D1: // PSRLW + case 0x1D5: // PMULLW + case 0x1D9: // PSUBUSW + case 0x1DD: // PADDUSW + case 0x1E1: // PSRAW + case 0x1E3: // PAVGW + case 0x1E4: // PMULHUW + case 0x1E5: // PMULHW + case 0x1E9: // PSUBSW + case 0x1EA: // PMINSW + case 0x1ED: // PADDSW + case 0x1EE: // PMAXSW + case 0x1F1: // PSLLW + case 0x1F6: // PSADBW + case 0x1F9: // PSUBW + case 0x1FD: // PADDW + UpdateXmmSizes(m, xt, 2, 2); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x166: // PCMPGTD + case 0x176: // PCMPEQD + case 0x172: // PSRLD,PSRAD,PSLLD + case 0x1D2: // PSRLD + case 0x1E2: // PSRAD + case 0x1F2: // PSLLD + case 0x1FA: // PSUBD + case 0x1FE: // PADDD + UpdateXmmSizes(m, xt, 4, 4); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x173: // PSRLQ,PSRLQ,PSRLDQ,PSLLQ,PSLLDQ + case 0x1D3: // PSRLQ + case 0x1D4: // PADDQ + case 0x1F3: // PSLLQ + case 0x1F4: // PMULUDQ + case 0x1FB: // PSUBQ + UpdateXmmSizes(m, xt, 8, 8); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x16B: // PACKSSDW + case 0x1F5: // PMADDWD + UpdateXmmSizes(m, xt, 4, 2); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x163: // PACKSSWB + case 0x167: // PACKUSWB + UpdateXmmSizes(m, xt, 1, 2); + UpdateXmmTypes(m, xt, kXmmIntegral, kXmmIntegral); + break; + case 0x128: // MOVAPS Vps Wps + if (IsModrmRegister(m->xedd->op.rde)) { + xt->type[RexrReg(m->xedd->op.rde)] = xt->type[RexbRm(m->xedd->op.rde)]; + xt->size[RexrReg(m->xedd->op.rde)] = xt->size[RexbRm(m->xedd->op.rde)]; + } + break; + case 0x129: // MOVAPS Wps Vps + if (IsModrmRegister(m->xedd->op.rde)) { + xt->type[RexbRm(m->xedd->op.rde)] = xt->type[RexrReg(m->xedd->op.rde)]; + xt->size[RexbRm(m->xedd->op.rde)] = xt->size[RexrReg(m->xedd->op.rde)]; + } + break; + case 0x16F: // MOVDQA Vdq Wdq + if (Osz(m->xedd->op.rde) && IsModrmRegister(m->xedd->op.rde)) { + xt->type[RexrReg(m->xedd->op.rde)] = xt->type[RexbRm(m->xedd->op.rde)]; + xt->size[RexrReg(m->xedd->op.rde)] = xt->size[RexbRm(m->xedd->op.rde)]; + } + break; + default: + return; + } +} diff --git a/tool/build/lib/xmmtype.h b/tool/build/lib/xmmtype.h new file mode 100644 index 00000000..00dc4576 --- /dev/null +++ b/tool/build/lib/xmmtype.h @@ -0,0 +1,21 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_XMMTYPE_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_XMMTYPE_H_ +#include "tool/build/lib/machine.h" + +#define kXmmIntegral 0 +#define kXmmDouble 1 +#define kXmmFloat 2 + +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct XmmType { + uint8_t type[16]; + uint8_t size[16]; +}; + +void UpdateXmmType(struct Machine *, struct XmmType *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_XMMTYPE_H_ */ diff --git a/tool/build/package.c b/tool/build/package.c index dfa7a161..bb6aa695 100644 --- a/tool/build/package.c +++ b/tool/build/package.c @@ -44,6 +44,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #include "libc/time/time.h" @@ -362,6 +363,7 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot, } void CloseObject(struct Object *obj) { + msync(obj->elf, obj->size, MS_SYNC); CHECK_NE(-1, munmap(obj->elf, obj->size)); } diff --git a/tool/viz/memzoom.c b/tool/viz/memzoom.c new file mode 100644 index 00000000..8a48b96e --- /dev/null +++ b/tool/viz/memzoom.c @@ -0,0 +1,940 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "dsp/scale/cdecimate2xuint8x8.h" +#include "libc/bits/bits.h" +#include "libc/bits/hilbert.h" +#include "libc/bits/morton.h" +#include "libc/bits/safemacros.h" +#include "libc/calls/calls.h" +#include "libc/calls/ioctl.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/struct/termios.h" +#include "libc/calls/struct/winsize.h" +#include "libc/calls/ucontext.h" +#include "libc/conv/conv.h" +#include "libc/conv/itoa.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/log/log.h" +#include "libc/macros.h" +#include "libc/nexgen32e/bsf.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/str/tpenc.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/poll.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" +#include "libc/sysv/consts/termios.h" +#include "libc/time/time.h" +#include "libc/unicode/unicode.h" +#include "third_party/getopt/getopt.h" + +#define USAGE \ + " [-hznmH] [-p PID] [PATH]\n\ +\n\ +DESCRIPTION\n\ +\n\ + Memory Viewer\n\ +\n\ +FLAGS\n\ +\n\ + -h help\n\ + -z zoom\n\ + -w white bg color\n\ + -m morton ordering\n\ + -H hilbert ordering\n\ + -n natural scrolling\n\ + -p PID shows process virtual memory\n\ + -f INT frames per second [default 10]\n\ +\n\ +SHORTCUTS\n\ +\n\ + z or + zoom\n\ + Z or - unzoom\n\ + ctrl+wheel zoom point\n\ + wheel scroll\n\ + l linearize\n\ + m mortonize\n\ + h hilbertify\n\ + n next mapping\n\ + N next mapping ending\n\ + p prev mapping\n\ + P prev mapping ending\n\ + k up\n\ + j down\n\ + b page up\n\ + space page down\n\ + g home\n\ + G end\n\ + q quit\n\ +\n" + +#define CTRL(C) ((C) ^ 0100) + +#define MAXZOOM 14 +#define COLOR 253 + +#define LINEAR 0 +#define MORTON 1 +#define HILBERT 2 + +#define INTERRUPTED 0x1 +#define RESIZED 0x2 + +#define MOUSE_LEFT_DOWN 0 +#define MOUSE_MIDDLE_DOWN 1 +#define MOUSE_RIGHT_DOWN 2 +#define MOUSE_LEFT_UP 4 +#define MOUSE_MIDDLE_UP 5 +#define MOUSE_RIGHT_UP 6 +#define MOUSE_LEFT_DRAG 32 +#define MOUSE_MIDDLE_DRAG 33 +#define MOUSE_RIGHT_DRAG 34 +#define MOUSE_WHEEL_UP 64 +#define MOUSE_WHEEL_DOWN 65 +#define MOUSE_CTRL_WHEEL_UP 80 +#define MOUSE_CTRL_WHEEL_DOWN 81 + +struct Ranges { + long i; + struct Range { + long a; + long b; + } p[512]; +}; + +static const signed char kThePerfectKernel[8] = {-1, -3, 3, 17, 17, 3, -3, -1}; + +static bool white; +static bool natural; +static bool mousemode; + +static int fd; +static int pid; +static int out; +static int fps; +static int zoom; +static int order; +static int action; + +static long tyn; +static long txn; +static long size; +static long offset; +static long lowest; +static long highest; +static long canvassize; +static long buffersize; +static long displaysize; + +static char *buffer; +static uint8_t *canvas; + +static struct stat st; +static struct Ranges ranges; +static struct termios oldterm; + +static char path[PATH_MAX]; +static char mapspath[PATH_MAX]; + +static int Write(const char *s) { + return write(out, s, strlen(s)); +} + +static void HideCursor(void) { + Write("\e[?25l"); +} + +static void ShowCursor(void) { + Write("\e[?25h"); +} + +static void EnableMouse(void) { + mousemode = true; + Write("\e[?1000;1002;1015;1006h"); +} + +static void DisableMouse(void) { + mousemode = false; + Write("\e[?1000;1002;1015;1006l"); +} + +static void LeaveScreen(void) { + Write("\e[H\e[J"); +} + +static void GetTtySize(void) { + struct winsize wsize; + wsize.ws_row = tyn + 1; + wsize.ws_col = txn; + getttysize(out, &wsize); + tyn = MAX(2, wsize.ws_row) - 1; + txn = MAX(17, wsize.ws_col) - 16; + tyn = rounddown2pow(tyn); + txn = rounddown2pow(txn); + tyn = MIN(tyn, txn); +} + +static void EnableRaw(void) { + struct termios term; + memcpy(&term, &oldterm, sizeof(term)); + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 1; + term.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON); + term.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL); + term.c_cflag &= ~(CSIZE | PARENB); + term.c_cflag |= CS8; + term.c_iflag |= IUTF8; + ioctl(out, TCSETS, &term); +} + +static void OnExit(void) { + LeaveScreen(); + ShowCursor(); + DisableMouse(); + ioctl(out, TCSETS, &oldterm); +} + +static void OnSigInt(int sig, struct siginfo *sa, struct ucontext *uc) { + action |= INTERRUPTED; +} + +static void OnSigWinch(int sig, struct siginfo *sa, struct ucontext *uc) { + action |= RESIZED; +} + +static void Setup(void) { + tyn = 80; + txn = 24; + action = RESIZED; + ioctl(out, TCGETS, &oldterm); + HideCursor(); + EnableRaw(); + EnableMouse(); + atexit(OnExit); + sigaction(SIGINT, &(struct sigaction){.sa_sigaction = OnSigInt}, NULL); + sigaction(SIGWINCH, &(struct sigaction){.sa_sigaction = OnSigWinch}, NULL); +} + +static noreturn void FailPath(const char *s, int rc) { + Write("error: "); + Write(s); + Write(": "); + Write(path); + Write("\n"); + exit(rc); +} + +static void SetExtent(long lo, long hi) { + lowest = lo; + highest = hi; + offset = MIN(hi, MAX(lo, offset)); +} + +static void Open(void) { + int err; + if ((fd = open(path, O_RDONLY)) == -1) { + FailPath("open() failed", errno); + } + fstat(fd, &st); + size = st.st_size; + SetExtent(0, size); +} + +static void *Allocate(size_t n) { + return mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, + 0); +} + +static void SetupCanvas(void) { + if (canvassize) { + munmap(canvas, canvassize); + munmap(buffer, buffersize); + } + displaysize = ROUNDUP(ROUNDUP(tyn * txn * (1ul << zoom), 16), 1ul << zoom); + canvassize = ROUNDUP(displaysize, FRAMESIZE); + buffersize = ROUNDUP(tyn * txn * 16 + PAGESIZE, FRAMESIZE); + canvas = Allocate(canvassize); + buffer = Allocate(buffersize); +} + +static long IndexSquare(long y, long x) { + switch (order) { + case LINEAR: + return y * txn + x; + case MORTON: + return morton(y, x); + case HILBERT: + return hilbert(txn, y, x); + default: + return 0; + } +} + +static long Index(long y, long x) { + long i; + if (order == LINEAR) { + i = 0; + } else { + i = x / tyn; + x = x % tyn; + } + return i * tyn * tyn + IndexSquare(y, x); +} + +static void PreventBufferbloat(void) { + long double now, rate; + static long double last; + now = nowl(); + rate = 1. / fps; + if (now - last < rate) { + dsleep(rate - (now - last)); + } + last = now; +} + +static bool HasPendingInput(void) { + struct pollfd fds[1]; + fds[0].fd = 0; + fds[0].events = POLLIN; + fds[0].revents = 0; + poll(fds, ARRAYLEN(fds), 0); + return fds[0].revents & (POLLIN | POLLERR); +} + +static int GetCurrentRange(void) { + int i; + if (ranges.i) { + for (i = 0; i < ranges.i; ++i) { + if (offset < ranges.p[i].a) return MAX(0, i - 1); + if (offset < ranges.p[i].b) return i; + } + return ranges.i - 1; + } else { + return -1; + } +} + +static void Move(long d) { + offset = MIN(highest, MAX(lowest, ROUNDDOWN(offset + d, 1L << zoom))); +} + +static void SetZoom(long y, long x, int d) { + long a, b, i; + if ((0 <= y && y < tyn) && (0 <= x && x < txn)) { + i = Index(y, x); + a = zoom; + b = MIN(MAXZOOM, MAX(0, a + d)); + zoom = b; + Move(i * (1L << a) - i * (1L << b)); + SetupCanvas(); + } +} + +static void OnZoom(long y, long x) { + SetZoom(y, x, +1); +} + +static void OnUnzoom(long y, long x) { + SetZoom(y, x, -1); +} + +static void OnUp(void) { + Move(-(txn * (1l << zoom))); +} + +static void OnDown(void) { + Move(txn * (1l << zoom)); +} + +static void OnPageUp(void) { + Move(-(txn * (tyn - 2) * (1l << zoom))); +} + +static void OnPageDown(void) { + Move(txn * (tyn - 2) * (1l << zoom)); +} + +static void OnHome(void) { + offset = lowest; +} + +static void OnEnd(void) { + offset = MAX(lowest, highest - txn * tyn * (1l << zoom)); +} + +static void OnLinear(void) { + order = LINEAR; + GetTtySize(); + SetupCanvas(); +} + +static void OnMorton(void) { + order = MORTON; + SetupCanvas(); +} + +static void OnHilbert(void) { + order = HILBERT; + SetupCanvas(); +} + +static void OnNext(void) { + int i; + if ((i = GetCurrentRange()) != -1) { + if (i + 1 < ranges.i) { + offset = ranges.p[i + 1].a; + } + } +} + +static void OnPrev(void) { + int i; + if ((i = GetCurrentRange()) != -1) { + if (i) { + offset = ranges.p[i - 1].a; + } + } +} + +static void OnNextEnd(void) { + long i, n; + if ((i = GetCurrentRange()) != -1) { + n = tyn * txn * (1L << zoom); + if (offset < ranges.p[i].b - n) { + offset = ranges.p[i].b - n; + } else if (i + 1 < ranges.i) { + offset = MAX(ranges.p[i + 1].a, ranges.p[i + 1].b - n); + } + } +} + +static void OnPrevEnd(void) { + long i, n; + if ((i = GetCurrentRange()) != -1) { + n = tyn * txn * (1L << zoom); + if (i) { + offset = MAX(ranges.p[i - 1].a, ranges.p[i - 1].b - n); + } + } +} + +static void OnMouse(char *p) { + int e, x, y; + struct Panel *ep; + e = strtol(p, &p, 10); + if (*p == ';') ++p; + x = min(txn, max(1, strtol(p, &p, 10))) - 1; + if (*p == ';') ++p; + y = min(tyn, max(1, strtol(p, &p, 10))) - 1; + e |= (*p == 'm') << 2; + switch (e) { + case MOUSE_WHEEL_UP: + if (natural) { + OnDown(); + OnDown(); + OnDown(); + } else { + OnUp(); + OnUp(); + OnUp(); + } + break; + case MOUSE_WHEEL_DOWN: + if (natural) { + OnUp(); + OnUp(); + OnUp(); + } else { + OnDown(); + OnDown(); + OnDown(); + } + break; + case MOUSE_CTRL_WHEEL_UP: + if (natural) { + OnZoom(y, x); + } else { + OnUnzoom(y, x); + } + break; + case MOUSE_CTRL_WHEEL_DOWN: + if (natural) { + OnUnzoom(y, x); + } else { + OnZoom(y, x); + } + break; + default: + break; + } +} + +static void ReadKeyboard(void) { + char buf[32], *p = buf; + memset(buf, 0, sizeof(buf)); + if (readansi(0, buf, sizeof(buf)) == -1) { + if (errno == EINTR) return; + exit(errno); + } + switch (*p++) { + case 'q': + exit(0); + case '+': + case 'z': + OnZoom(0, 0); + break; + case '-': + case 'Z': + OnUnzoom(0, 0); + break; + case 'b': + OnPageUp(); + break; + case 'n': + OnNext(); + break; + case 'p': + OnPrev(); + break; + case 'N': + OnNextEnd(); + break; + case 'P': + OnPrevEnd(); + break; + case ' ': + case CTRL('V'): + OnPageDown(); + break; + case 'g': + OnHome(); + break; + case 'G': + OnEnd(); + break; + case 'k': + case CTRL('P'): + OnUp(); + break; + case 'j': + case CTRL('N'): + OnDown(); + break; + case 'l': + OnLinear(); + break; + case 'm': + if (order == MORTON) { + OnLinear(); + } else { + OnMorton(); + } + break; + case 'M': + if (mousemode) { + DisableMouse(); + } else { + EnableMouse(); + } + break; + case 'h': + case 'H': + if (order == HILBERT) { + OnLinear(); + } else { + OnHilbert(); + } + break; + case '\e': + switch (*p++) { + case 'v': + OnPageUp(); + break; + case '[': + switch (*p++) { + case '<': + OnMouse(p); + break; + case 'A': + OnUp(); + break; + case 'B': + OnDown(); + break; + case 'F': + OnEnd(); + break; + case 'H': + OnHome(); + break; + case '1': + switch (*p++) { + case '~': + OnHome(); + break; + default: + break; + } + break; + case '4': + switch (*p++) { + case '~': + OnEnd(); + break; + default: + break; + } + break; + case '5': + switch (*p++) { + case '~': + OnPageUp(); + break; + default: + break; + } + break; + case '6': + switch (*p++) { + case '~': + OnPageDown(); + break; + default: + break; + } + break; + case '7': + switch (*p++) { + case '~': + OnHome(); + break; + default: + break; + } + break; + case '8': + switch (*p++) { + case '~': + OnEnd(); + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } +} + +static void LoadRanges(void) { + char b[512]; + struct Range range; + int i, t, n, fd, err; + if ((fd = open(mapspath, O_RDONLY)) == -1) { + err = errno; + Write("error: process died\n"); + exit(err); + } + t = 0; + range.a = 0; + range.b = 0; + ranges.i = 0; + for (;;) { + if ((n = read(fd, b, sizeof(b))) == -1) exit(1); + if (!n) break; + for (i = 0; i < n; ++i) { + switch (t) { + case 0: + if (isxdigit(b[i])) { + range.a <<= 4; + range.a += hextoint(b[i]); + } else if (b[i] == '-') { + t = 1; + } + break; + case 1: + if (isxdigit(b[i])) { + range.b <<= 4; + range.b += hextoint(b[i]); + } else if (b[i] == ' ') { + t = 2; + } + break; + case 2: + if (b[i] == '\n') { + if (ranges.i < ARRAYLEN(ranges.p)) { + ranges.p[ranges.i++] = range; + } + range.a = 0; + range.b = 0; + t = 0; + } + break; + default: + unreachable; + } + } + } + close(fd); + if (ranges.i) { + SetExtent(ranges.p[0].a, ranges.p[ranges.i - 1].b); + } else { + SetExtent(0, 0); + } +} + +static int InvertXtermGreyscale(int x) { + return -(x - 232) + 255; +} + +static void Render(void) { + char *p; + int c, fg2, rc, fg; + long i, y, x, w, n, got; + p = buffer; + p = stpcpy(p, "\e[H"); + for (y = 0; y < tyn; ++y) { + fg = -1; + for (x = 0; x < txn; ++x) { + c = canvas[Index(y, x)]; + if (c < 32) { + fg2 = 237 + c * ((COLOR - 237) / 32.); + } else if (c >= 232) { + fg2 = COLOR + (c - 232) * ((255 - COLOR) / (256. - 232)); + } else { + fg2 = COLOR; + } + if (fg2 != fg) { + fg = fg2; + if (white) { + fg = InvertXtermGreyscale(fg); + } + p = stpcpy(p, "\e[38;5;"); + p += int64toarray_radix10(fg, p); + *p++ = 'm'; + } + w = tpenc(kCp437[c]); + do { + *p++ = w & 0xff; + w >>= 8; + } while (w); + } + p = stpcpy(p, "\e[0m "); + p += uint64toarray_radix16(offset + y * txn * (1ul << zoom), p); + p = stpcpy(p, "\e[K\r\n"); + } + p = stpcpy(p, "\e[7m\e[K"); + n = strlen(path); + if (n > txn - 3 - 1 - 7) { + p = mempcpy(p, path, txn - 1 - 7 - 3); + p = stpcpy(p, "..."); + } else { + p = stpcpy(p, path); + for (i = n; i < txn - 1 - 7; ++i) { + *p++ = ' '; + } + } + p = stpcpy(p, " memzoom\e[0m "); + if (!pid) { + p += uint64toarray_radix10(MIN(offset / (long double)size * 100, 100), p); + p = stpcpy(p, "%-"); + p += uint64toarray_radix10( + MIN((offset + tyn * txn * (1l << zoom)) / (long double)size * 100, 100), + p); + p = stpcpy(p, "% "); + } + p += uint64toarray_radix10(1L << zoom, p); + p = stpcpy(p, "x\e[J"); + PreventBufferbloat(); + for (i = 0, n = p - buffer; i < n; i += got) { + got = 0; + if ((rc = write(out, buffer + i, n - i)) == -1) { + if (errno == EINTR) continue; + exit(errno); + } + got = rc; + } +} + +static void Zoom(long have) { + long i, n, r; + n = canvassize; + for (i = 0; i < zoom; ++i) { + cDecimate2xUint8x8(n, canvas, kThePerfectKernel); + n >>= 1; + } + if (n < tyn * txn) { + memset(canvas + n, 0, canvassize - n); + } + if (have != -1) { + n = have / (1L << zoom); + i = n / txn; + r = n % txn; + if (r) ++i; + if (order == LINEAR) { + for (; i < tyn; ++i) { + canvas[txn * i] = '~'; + } + } + } +} + +static void FileZoom(void) { + long have; + have = MIN(displaysize, size - offset); + have = pread(fd, canvas, have, offset); + have = MAX(0, have); + memset(canvas + have, 0, canvassize - have); + Zoom(have); + Render(); +} + +static void RangesZoom(void) { + long a, b, c, d, i; + LoadRanges(); + memset(canvas, 1, canvassize); + a = offset; + b = MIN(highest, offset + tyn * txn * (1ul << zoom)); + for (i = 0; i < ranges.i; ++i) { + if ((a >= ranges.p[i].a && a < ranges.p[i].b) || + (b >= ranges.p[i].a && b < ranges.p[i].b) || + (a < ranges.p[i].a && b >= ranges.p[i].b)) { + c = MAX(a, ranges.p[i].a); + d = MIN(b, ranges.p[i].b); + pread(fd, canvas + (c - offset), d - c, c); + } + } + Zoom(-1); + Render(); +} + +static void MemZoom(void) { + char *p; + int c, fg2, rc, fg; + long i, n, r, w, y, x, got, have; + do { + if (action & INTERRUPTED) { + break; + } + if (action & RESIZED) { + GetTtySize(); + SetupCanvas(); + action &= ~RESIZED; + } + if (HasPendingInput()) { + ReadKeyboard(); + continue; + } + if (pid) { + RangesZoom(); + } else { + FileZoom(); + } + } while (!(action & INTERRUPTED)); +} + +static noreturn void PrintUsage(int rc) { + Write("SYNOPSIS\n\n "); + Write(program_invocation_name); + Write(USAGE); + exit(rc); +} + +static void GetOpts(int argc, char *argv[]) { + int opt; + char *p; + fps = 10; + while ((opt = getopt(argc, argv, "hzHnwf:p:")) != -1) { + switch (opt) { + case 'z': + ++zoom; + break; + case 'n': + natural = true; + break; + case 'm': + order = MORTON; + break; + case 'H': + order = HILBERT; + break; + case 'w': + white = true; + break; + case 'f': + fps = strtol(optarg, NULL, 0); + fps = MAX(1, fps); + break; + case 'p': + if (strcmp(optarg, "self") == 0) { + pid = getpid(); + } else { + pid = strtol(optarg, NULL, 0); + } + break; + case 'h': + PrintUsage(EXIT_SUCCESS); + default: + PrintUsage(EX_USAGE); + } + } + if (pid) { + p = stpcpy(path, "/proc/"); + p += int64toarray_radix10(pid, p); + stpcpy(p, "/mem"); + p = stpcpy(mapspath, "/proc/"); + p += int64toarray_radix10(pid, p); + stpcpy(p, "/maps"); + } else { + if (optind == argc) { + PrintUsage(EX_USAGE); + } + if (!memccpy(path, argv[optind], '\0', sizeof(path))) { + PrintUsage(EX_USAGE); + } + } +} + +int main(int argc, char *argv[]) { + if (!NoDebug()) showcrashreports(); + out = 1; + GetOpts(argc, argv); + Open(); + Setup(); + MemZoom(); + return 0; +} diff --git a/tool/viz/printimage.c b/tool/viz/printimage.c index 30798967..a14752e8 100644 --- a/tool/viz/printimage.c +++ b/tool/viz/printimage.c @@ -364,7 +364,7 @@ void WithImageFile(const char *path, void fn(long yn, long xn, unsigned char RGB[3][yn][xn])) { struct stat st; void *map, *data, *data2; - int fd, yn, xn, cn, dyn, dxn; + int fd, yn, xn, cn, dyn, dxn, syn, sxn; CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path); CHECK_NE(-1, fstat(fd, &st)); CHECK_GT(st.st_size, 0); @@ -387,10 +387,26 @@ void WithImageFile(const char *path, cn = 3; } if (g_flags.height && g_flags.width) { + syn = yn; + sxn = xn; dyn = g_flags.height; dxn = g_flags.width; + while (HALF(syn) > dyn || HALF(sxn) > dxn) { + if (HALF(sxn) > dxn) { + Magikarp2xX(yn, xn, data, syn, sxn); + Magikarp2xX(yn, xn, (char *)data + yn * xn, syn, sxn); + Magikarp2xX(yn, xn, (char *)data + yn * xn * 2, syn, sxn); + sxn = HALF(sxn); + } + if (HALF(syn) > dyn) { + Magikarp2xY(yn, xn, data, syn, sxn); + Magikarp2xY(yn, xn, (char *)data + yn * xn, syn, sxn); + Magikarp2xY(yn, xn, (char *)data + yn * xn * 2, syn, sxn); + syn = HALF(syn); + } + } data = EzGyarados(3, dyn, dxn, gc(memalign(32, dyn * dxn * 3)), cn, yn, xn, - data, 0, cn, dyn, dxn, yn, xn, 0, 0, 0, 0); + data, 0, cn, dyn, dxn, syn, sxn, 0, 0, 0, 0); yn = dyn; xn = dxn; }