Hat ein 16-Bit- oder 36-Bit-Computerbefehlssatz jemals 4x4- oder 6x6-Bitmatrixoperationen enthalten?
Die 64-Bit- MMIX-Architektur von Donald Knuth enthält mehrere neuartige Anweisungen, die matrixweise auf einer 8x8-Quadratmatrix ( MOR, MXOR) arbeiten.
(MMIX hat auch Anweisungen wie diese BDIF, die vektorweise mit 8x 8-Bit-Ganzzahlen arbeiten, was weniger neu ist; x86 macht das ganz gut.)
Die Behandlung Ihres 64-Bit-Wortes als quadratische Matrix ist nur möglich, wenn die Wortgröße ein perfektes Quadrat ist.
Früher gab es Computer mit einer Wortlänge von 36 Bit . Das ist bekanntlich genug, um 6x 6-Bit-Zeichen (vor ASCII) in einem einzigen Wort zu speichern. Hat jemals ein historischer 36-Bit-Computer Operationen angeboten, die am besten durch das Lesen von Maschinenwörtern als 6x6-Matrizen verstanden wurden?
Wie wäre es mit einem historischen 16-Bit-Computer?
Neben komplizierten Anweisungen wie MMIXs MORund wäre MXORdas einfachste Beispiel für eine "Matrixoperation" in dem Sinne, wie ich meine, eine unäre TRANSPOSEOperation:
TRANSPOSE(1001'1010'1010'1011) = 1111'0000'0111'1001
TRANSPOSE(1001'0010'1011'0100) = 1010'0001'0110'1010
Antworten
Ich weiß nicht, ob es sich um einen historischen 16-Bit-Computer handelt, aber es gab eine Reihe von 80287-Klonen. Einer von ihnen von IIT fügte einen F4x4-Befehl hinzu, der auf dem gesamten FP-Stapel arbeitete, um Matrixoperationen auszuführen (der IIT-Chip hatte nicht einen, sondern vier Stapel mit jeweils acht FPU-Registern).
Ein Freund von mir hatte damals einen dieser Coprozessoren und es kam mit einem Demo-Programm, das einen Geschwindigkeitstest dieser F4x4-Anweisung zeigte. Das Leafsheet, das als Anpassungs- und Benutzerhandbuch diente, erwähnte diese Funktion ebenfalls.
Die einzigen Informationen, die ich bisher gefunden habe, stammen aus der Datei COPRO16A.TXT von Norbert Juffa . Auszüge aus diesem Dokument sind:
Der IIT 2C87 bietet zusätzliche Funktionen, die auf keinem anderen 287-Chip verfügbar sind [38]. Es verfügt über 24 vom Benutzer zugängliche Gleitkommaregister, die in drei Registerbänken organisiert sind. Zusätzliche Anweisungen (FSBP0, FSBP1, FSBP2) ermöglichen den Wechsel von einer Bank zu einer anderen. (Übertragungen zwischen Registern in verschiedenen Bänken werden jedoch nicht unterstützt, sodass diese Funktion für sich genommen nur von begrenztem Nutzen ist. Außerdem scheint es nur ein Statusregister zu geben (das den oberen Stapelzeiger enthält), sodass es manuell geladen und gespeichert werden muss beim Umschalten zwischen Banken mit einer anderen Anzahl verwendeter Register [40]). Der Hauptzweck der Registerbank besteht darin, den vierten zusätzlichen Befehl des 2C87 (F4X4) zu unterstützen, der eine vollständige Multiplikation einer 4x4-Matrix mit einem 4x1-Vektor ausführt, eine Operation, die in 3D-Grafikanwendungen üblich ist [39].Die eingebaute Multiplikationsmatrix beschleunigt diesen Vorgang im Vergleich zu einer nach Angaben des Herstellers programmierten Lösung um den Faktor 6 bis 8 [38]. Tests zeigen, dass die Beschleunigung tatsächlich in diesem Bereich liegt [40]. Für den 3C87 habe ich die Ausführungszeit von F4X4 mit etwa 280 Taktzyklen gemessen. Die Ausführungszeit auf dem 2C87 sollte etwas länger sein - ich schätze, dass sie aufgrund des höheren CPU-NDP-Kommunikationsaufwands bei der Befehlsausführung in 286/287 Systemen (~ 45-50 Taktzyklen) im Vergleich zu 386/387 bei etwa 310 Taktzyklen liegt Systeme (~ 16-20 Taktzyklen). So wünschenswert der F4X4-Befehl auch erscheinen mag, es gibt nur sehr wenige Anwendungen, die ihn verwenden, wenn zur Laufzeit ein IIT-Coprozessor erkannt wird (darunter der Silver Screen von Schroff Development und der Fast-CAD 3-D von Evolution Computing [25]). .
Und eine Routine, die zeigt, wie man die F4x4-Anweisung verwendet:
;---------------------------------------------------------------------
;
; IIT_MUL_4x4 multiplicates a four-by-four matrix by an array of four
; dimensional vectors. This operation is needed for 3D transformations
; in graphics data processing. There are arrays for each component of
; a vector. Thus there is an array containing all the x components,
; another containing all the y components and so on. Each component is
; an 8 byte IEEE floating-point number. Two indices into the array of
; vectors are given. The first is the index of the vector that will be
; processed first, the second is the index of the vector processed
; last. This subroutine uses the special instructions only available
; on IIT coprocessors to provide fast matrix multiply capabilities.
; So make sure to use it only on IIT coprocessors.
;
;---------------------------------------------------------------------
IIT_MUL_4x4 PROC NEAR
AddrX EQU DWORD PTR [BP+24] ; address of X component array
AddrY EQU DWORD PTR [BP+20] ; address of Y component array
AddrZ EQU DWORD PTR [BP+16] ; address of Z component array
AddrW EQU DWORD PTR [BP+12] ; address of W component array
AddrT EQU DWORD PTR [BP+8] ; addr. of 4x4 transf. matrix
F EQU WORD PTR [BP+6] ; first vector to process
K EQU WORD PTR [BP+4] ; last vector to process
RetAddr EQU WORD PTR [BP+2] ; return address saved by call
SavdBP EQU WORD PTR [BP+0] ; saved frame pointer
SavdDS EQU WORD PTR [BP-2] ; caller's data segment
Ctrl87 EQU WORD PTR [BP-4] ; caller's 80x87 control word
PUSH BP ; save TURBO-Pascal frame ptr
MOV BP, SP ; new frame pointer
PUSH DS ; save TURBO-Pascal data seg.
SUB SP, 2 ; make local variabe
FSTCW [Ctrl87] ; save 80x87 ctrl word
LES SI, AddrT ; ptr to transformation matrix
FINIT ; initialize coprocessor
FSBP2 ; set register bank 2
FLD QWORD PTR ES:[SI] ; load a[0,0]
FLD QWORD PTR ES:[SI+32] ; load a[1,0]
FLD QWORD PTR ES:[SI+64] ; load a[2,0]
FLD QWORD PTR ES:[SI+96] ; load a[3,0]
FLD QWORD PTR ES:[SI+8] ; load a[0,1]
FLD QWORD PTR ES:[SI+40] ; load a[1,1]
FLD QWORD PTR ES:[SI+72] ; load a[2,1]
FLD QWORD PTR ES:[SI+104] ; load a[3,1]
FINIT ; initialize coprocessor
FSBP1 ; set register bank 1
FLD QWORD PTR ES:[SI+16] ; load a[0,2]
FLD QWORD PTR ES:[SI+48] ; load a[1,2]
FLD QWORD PTR ES:[SI+80] ; load a[2,2]
FLD QWORD PTR ES:[SI+112] ; load a[3,2]
FLD QWORD PTR ES:[SI+24] ; load a[0,3]
FLD QWORD PTR ES:[SI+56] ; load a[1,3]
FLD QWORD PTR ES:[SI+88] ; load a[2,3]
FLD QWORD PTR ES:[SI+120] ; load a[3,3]
; transformation matrix loaded
MOV AX, F ; index of first vector
MOV DX, K ; index of last vector
MOV BX, AX ; index 1st vector to process
MOV CL, 3 ; component has 8 (2**3) bytes
SHL BX, CL ; compute offset into arrays
FINIT ; initialize coprocessor
FSBP0 ; set register bank 0
$mat_loop:LES SI, AddrW ; addr. of W component array FLD QWORD PTR ES:[SI+BX] ; W component current vector LES SI, AddrZ ; addr. of Z component array FLD QWORD PTR ES:[SI+BX] ; Z component current vector LES SI, AddrY ; addr. of Y component array FLD QWORD PTR ES:[SI+BX] ; Y component current vector LES SI, AddrX ; addr. of X component array FLD QWORD PTR ES:[SI+BX] ; X component current vector F4X4 ; mul 4x4 matrix by 4x1 vector INC AX ; next vector MOV DI, AX ; next vector SHL DI, CL ; offset of vector into arrays FSTP QWORD PTR ES:[SI+BX] ; store X comp. of curr. vect. LES SI, AddrY ; address of Y component array FSTP QWORD PTR ES:[SI+BX] ; store Y comp. of curr. vect. LES SI, AddrZ ; address of Z component array FSTP QWORD PTR ES:[SI+BX] ; store Z comp. of curr. vect. LES SI, AddrW ; address of W component array FSTP QWORD PTR ES:[SI+BX] ; store W comp. of curr. vect. MOV BX, DI ; ofs nxt vect. in comp. arrays CMP AX, DX ; nxt vector past upper bound? JLE $mat_loop ; no, transform next vector
FLDCW [Ctrl87] ; restore orig 80x87 ctrl word
ADD SP, 2 ; get rid of local variable
POP DS ; restore TP data segment
POP BP ; restore TP frame pointer
RET 24 ; pop parameters and return
IIT_MUL_4x4 ENDP
CODE ENDS
END
Ich denke, die große Frage, die Sie hier stellen müssen, lautet: Wofür wäre eine solche Anweisung nützlich gewesen? Einzelbit-Datentypen passen normalerweise nicht zu Matrixoperationen.
Ich habe mir einige Beispiele angesehen, in denen die MMIX-Anweisungen verwendet werden, und sie scheinen angesichts der Komplexität der Hardware nicht sehr überzeugend zu sein. Wenn Sie beispielsweise eine ROLAnweisung wünschen , können Sie SHLder Implementierung einer Anweisung einige Tore hinzufügen und alle Gymnastik vermeiden, die erforderlich ist, um sie mit einer MORAnweisung zu emulieren . Ein weiteres Beispiel besteht darin, eine schmale Zeichenfolge (z. B. ASCII) in eine breitere (z. B. UTF-16) zu unterteilen, was mir als nicht häufig genug erscheint, um die Verwendung von etwas Klügerem als der offensichtlichen Skalarschleife zu rechtfertigen.
Die besten mir bekannten Beispiele für diese Art von Operation stammen von relativ neuen CPUs mit SIMD-Einheiten wie ARM NEON (eine 32-Bit-Architektur mit 64-Bit- und 128-Bit-SIMD-Registern). Diese umfassen häufig sowohl "horizontale" (z. B. Summe aller Elemente in einem einzelnen Register) als auch "vertikale" (z. B. zwei Register elementweise multiplizieren und zu einem dritten akkumulieren) Operationen, die verwendet werden können, um die Matrixarithmetik durch Kombinieren von a effizient zu unterstützen relativ kleine Anzahl von Anweisungen. Es gibt auch Anweisungen zum Verschachteln und Aufheben der Verschachtelung von Daten (auch bekannt als Zip- und Unzip-Operationen), die zum Transponieren von Matrizen sehr nützlich sein können.