събота, 1 юни 2013 г.

SBCL за ARM Част II

Продължение на това: Част I

Гледайки build-order.lisp-expr, първия изцяло платформено зависим файл, който се зарежда е src/compiler/arm/params.lisp. Тук се дефинират основни [константни] параметри на платформата, като например:

  • (def!constant n-word-bits 32) -- брой битове в една дума, където под дума се разбира 1 lisp descriptor. Какво точно е lisp descriptor? Това е основната "кукичка" към данните в SBCL. Ако данната се събира в 1 дескриптор, тя е самодостатъчна (такива са например т.н. fixnum числа). Ако данната не се събира в 1 дескриптор, то дескриптора съдържа пойнтер към паметта, където се съдържа останалата част от данните. И в двата случая една част от дескриптора указва типа на данните, но за това после. Забележете, че тук (и на много други места) се използва def!constant вместо стандартното defconstant, тък като тази версия се грижи да прави необходимите неща в зависимост от това кога точно се изпълнява (напр. по време на компилиране на крос-компилатора, дефинира не една, а две константи -- едната за да може host компилатора да знае за тази константа и да я разбира в последствие, другата за самия cross компилатор, който също трябва да си я запише някъде и да я използва когато той компилира);
  • (def!constant n-machine-word-bits 32) -- брой битове в думата, където под дума се разбира естествения тип данни за съответната архитектура. Аз лично не знам кому е нужно n-word-bits да е различно от n-machine-word-bits, но това е факт за alpha порт-а.
  • (def!constant n-byte-bits 8) -- малко безмислен параметър съгласно съвременните разбирания, но като се има предвид, че SBCL наследява code base от началото на 80-те години на миналия век, който пък не е ясно какво точно наследява, мога да си представя случаи, в които байтът не е бил 8 бита...
  • следващите няколко дефинират floating point форматите, които се поддържат native от платформата; в случая с ARM те изцяло съвпадат с IEEE 754 single и double float (при x86 напр. има и long-double, който се поддържа от хардуера, но тук -- не):
  • (def!constant float-sign-shift 31) -- колко наляво трябва да се шифтне бита за знак, за да застане на мястото си във floating point формата. Използва се и за single и за double, като за double  се прилага за старшата дума;
  • (def!constant single-float-bias 126)-- колко трябва да се прибави към експонентата, когато тя се кодира в съответния формат (виж IEEE 754);
  • (defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -- коя част от кодираните данни заема експонентата. (byte size pos) е стандартна lisp конструкция, която избира size на брой бита, започвайки от позиция pos. Странният начин за дефиниране на константата тук (и на други места) е свързан с факта, че това всъщност не е точно immediate константа, а е по-сложен Lisp обект, чиято стойност по време на компилация и после по време на зареждане може да се различава, която пък противоречи на смисъла "константа". Затова се ползва къстъм версия на defconstant.
  • (def!constant single-float-normal-exponent-min 1)
  • (def!constant single-float-normal-exponent-max 254) -- минимална и максимална стойност на експонентата за нормализирани числа;
  • (def!constant single-float-hidden-bit (ash 1 23)) -- съгласно IEEE 754 най-старшия бит на мантисата по подразбиране е 1 и не се записва;
  • (def!constant single-float-trapping-nan-bit (ash 1 22)) -- пак съгласно IEEE 754, когато има NaN (not-a-number), който води до грешка (trapping nan), то съответния бит е вдигнат;
  • Аналогични константи се дефинират и за double
Друг набор от изключително важни параметри, дефинирани тук е списък с адресите и размерите на различните "пространства". SBCL разделя паметта, която вижда, на няколко различни области, всяка с различно предназначение. Най-важните са т.н. static и dynamic space, като в static space се записват неща, които са предварително (разбирай -- още по време на компилацията на компилатора) алокирани и не се местят, докато в dynamic space се записват всички динамично създадени обекти. Както се досещате, в dynamic space-а работи garbage collector–а. В SBCL има имплементирани 2 гарбидж колектора -- класическият Cheney GC (и като казвам класически имам предвид, че е публикуван през 1970 г.) и по-нов, generational conservative garbage collector (gencgc). В зависимост от операционната система и вида GC тези пространства имат различни адреси и размери, при това се нагласят емпирично. За целта обаче трябва да тръгне SBCL на таргет машината, т.е. емпирично ще разберем правилните стойности доста по-късно, чак към момента на пускане на make-target-2.sh. Засега слагаме някакви стойности, колкото да ги има.

Следва списък от символи (разбирай -- променливи и функции), които да се запишат в static space-а, при това списъка е подреден. Тъй като те са непреместваеми, SBCL знае как да ги реферира като събере началото на статичното пространство с число, формирано от поредния номер на символа, умножено по размера на символа в паметта (който за щастие е константен ;-)). За момента не знаем кои символи ще ни трябват и кои не -- оставяме ги така, както са в X86 порта.

С това src/compiler/arm/params.lisp приключва. Ще трябва да го навестим някъде в бъдещето, когато стигнем до make-target-2.sh. Но засега -- това е.


Няма коментари: