Многобайтовое хранение и выборка в Forth - как реализовать?

При использовании больших массивов было бы неплохо иметь возможность настроить массив для определенного количества байтов на число. В основном, я хочу, чтобы быстрые подпрограммы считывали такие скорректированные многобайтовые числа в синглы в стеке и наоборот, чтобы хранить синглы в массиве, настроенном на определенное количество байтов. В 64-битной системе нужны другие однозначные массивы, кроме одного байта (c@ c!) И восьми байтов (@!).

Так как реализовать

cs@ ( ad b -- n )
cs! ( n ad b -- )

где b - количество байтов. Слово сс! кажется, работает как

: cs! ( n ad b -- )  >r sp@ cell+ swap r> cmove drop ;

но как насчет cs@ и как это сделать на чистом ANS Forth без sp@ или подобных слов?

3 ответа

Комитет Forth200*x* потратил довольно много времени на разработку набора слов доступа к памяти, который подойдет. Пока что мы не включили его в стандарт из-за его размера.

\ little-endian (eg. pc, android)
: mb! ( n ad i -- )  2>r here ! here 2r> cmove ;
: mb@ ( ad i -- n )  here 0 over ! swap cmove here @ ;

\ big-endian (eg. mac)
: mb! ( n ad i -- )  2>r here ! here cell + r@ - 2r> cmove ;
: mb@ ( ad i -- n )  here 0 over ! cell + over - swap cmove here @ ;

\ little-endian test
1 here ! here c@ negate .

Конечно ЗДЕСЬ может быть любой буфер одной ячейки.

Спасибо ruvim за разбор процесса вперед!

Совместимый способ заключается в использовании C@ и побитовые операции. Чтобы использовать тот же порядок байтов в памяти, что и в системе Forth, необходимо определить порядок байтов и скомпилировать подходящие версии определенных определений.

\ These definitions use little-endian format in memory.
\ Assumption: char size and address unit size equal to 1 octet.

: MB! ( x addr u -- )
  ROT >R  OVER +  SWAP
  BEGIN  2DUP U>  WHILE  R> DUP 8 RSHIFT >R OVER C! 1+ REPEAT
  2DROP RDROP
;
: MB@ ( addr u -- x )
  0 >R  OVER +
  BEGIN  2DUP U<  WHILE  1- DUP C@ R> 8 LSHIFT OR >R  REPEAT
  2DROP R>
;

Для более высокой производительности может быть лучше использовать специфические функции реализации (включая W@, T@, Q@, SP@ и т. д.) или даже встроенный Forth-ассемблер.

Обратите внимание, что прямое определение через DO Цикл обычно имеет худшую производительность (зависит от оптимизатора; 10% в SP-Forth/4.21). Код для справки:

: MB! ( x addr u -- )
  OVER + SWAP ?DO DUP I C! 8 RSHIFT LOOP DROP
;
: MB@ ( addr u -- x )
  DUP 0= IF NIP EXIT THEN
  0 -ROT
  1- OVER + DO 8 LSHIFT I C@ OR -1 +LOOP
;

Мы не можем использовать ?DO во втором случае из-за уменьшения индекса цикла и +LOOP семантика: он покидает круг, когда индекс пересекает "границу между пределом цикла минус один и пределом цикла".

Другие вопросы по тегам