
Este artículo es la conclusión lógica de una
serie de artículos de "escalada Elbrus" sobre la introducción de
Embox a la
arquitectura del procesador Elbrus (E2K) . Por qué una conclusión lógica, porque como resultado, fue posible ejecutar a través de telnet una aplicación que muestra la imagen en la pantalla, es decir, para lograr el funcionamiento completo de Embox en esta arquitectura. La investigación adicional difícilmente puede considerarse una introducción, aunque, por supuesto, queda mucho por aclarar. Y la arquitectura en sí tiene muchas características interesantes, que tampoco se entienden actualmente. En este artículo, nos centraremos en la organización de la memoria virtual, tocaremos PCI, hablaremos un poco sobre una tarjeta de red y tocaremos una tarjeta de video en un hardware específico que tenemos.
Para aquellos que son demasiado flojos para leer el artículo, les daré de inmediato un breve video con los resultados.
Y ahora, para aquellos que estén interesados, revelaremos los detalles técnicos que pudimos entender en el proceso.
Memoria virtual
Nuestro error de pila
Comencemos con la memoria virtual. En realidad, esto es lo que resolvimos en el
artículo anterior
de la serie. Vale la pena recordar de inmediato por qué necesitábamos memoria virtual, porque Embox puede funcionar sin ella. Es simple: la cosa es el almacenamiento en caché. Vidyaha funcionó, pero tuvo que escribir lo mismo dos veces en la memoria de video para una recuperación de imagen confiable. Por supuesto, era posible lidiar con la memoria caché, pero nuestros ejemplos implican el uso de memoria de video directamente desde una aplicación de usuario, sin ningún elemento nuclear como la administración de la memoria caché, por lo que fue correcto aprender a asignar la memoria como no almacenable en caché. Lo mismo se puede hacer en Linux mapeando fb (
ejemplo ).
Vale la pena señalar que aunque no escribimos sobre Elbrus durante mucho tiempo y podría parecer que MMU en esta arquitectura es una especie de súper complicado, pero la cosa es diferente. De hecho, agregamos apoyo en el verano, simplemente no llegamos a nuestras manos para escribir sobre ello. Pasamos mucho tiempo (varios meses) debido a nuestro estúpido error. Este error incluso se cometió en el título del artículo ("O nunca olvides lo que obtuviste durante la inteligencia"). Estamos hablando de pilas con las que tratamos bastante bien y lo describimos en el artículo Climbing
Elbrus - Reconnaissance. Parte técnica 1. Registros, pilas y otros detalles técnicos " . Sufrimos durante mucho tiempo, perdiendo estúpidamente el hecho de que tomamos la pila inicial (en la que se inicializa el sistema) desde algún lugar fuera, y mapeamos todo. lo que necesitamos para que Embox funcione, no mapeamos estos datos.
Debajo del gato, le daré una nueva función e2k_entry, descrita en el segundo
artículo de la serie .
Si lo desea, puede comparar.
__attribute__ ((__section__(".e2k_entry"))) void e2k_entry(struct pt_regs *regs) { if (entries_count >= CPU_COUNT) { e2k_trap_handler(regs); RESTORE_COMMON_REGS(regs); E2K_DONE; } e2k_wait_all(); entries_count = __e2k_atomic32_add(1, &entries_count); if (entries_count > 1) { while(!sync_count); context_init(&cpu_ctx[0], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, cpu_idle, idle_stack, sizeof(idle_stack)); context_switch(&cpu_ctx_prev[0], &cpu_ctx[0]); } context_init(&cpu_ctx[1], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, e2k_kernel_start, &_stack_top, KERNEL_STACK_SZ); sync_count = __e2k_atomic32_add(1, &sync_count); context_switch(&cpu_ctx_prev[1], &cpu_ctx[1]); }
Solo explicaré que ahora usamos las funciones context_init () y context_switch () solo para cambiar la pila a la memoria en el espacio Embox. Y hacemos esto para todos los núcleos, incluidos los que no se utilizan.
Organización MMU
Ahora hablaré un poco sobre la organización de MMU en la arquitectura E2k.
En general, la arquitectura MMU es bastante común y tiene tablas de cuatro niveles (o tres cuando se usa una página de 4 MB).
Hay varios registros de servicio en la arquitectura E2k, se accede a ellos mediante comandos de acceso a espacios alternativos, así como al espacio de E / S que se describe brevemente en el artículo
"Embox comienza a escalar Elbrus" .
Necesitaremos tales registros:
#define MMU_REG_CR 0x00 #define MMU_REG_CONT 0x10 #define MMU_REG_CR3_RG 0x20 #define MMU_REG_ELB_PTB 0x30 #define MMU_REG_ROOT_PTB 0x40 /
En realidad, este es un registro de control, un registro de número de contexto, un registro raíz de tablas y un poco oscuro MMU_REG_ELB_PTB. Comencemos con esto, este registro debe establecerse en algún valor, el procesador utilizará los siguientes 512 GB para las necesidades del equipo, y estas direcciones no estarán disponibles para el programador. Proporcionaré explicaciones de la carta del especialista de ICST, difícilmente puedo explicar mejor:
En Linux, configuramos MMU_ELB_PTB en 0xff1 << 39, y luego
área superior de la memoria virtual (0xff8000000000 - 0xffffffffffff)
reservado para las necesidades de equipos, a saber, TLB. Cada página
la tabla de páginas (TS) obtiene su dirección única en esta área,
Además, estas direcciones se obtienen fácilmente de la dirección en la que el programa
apeló a la memoria. Y desde TLB almacena asignaciones de direcciones virtuales
físico, esto le permite almacenar en caché en el mismo búfer TLB
difunde no solo para las direcciones de los usuarios, sino también para el propio vehículo.
En aquellos procesadores / arquitecturas donde se realizan TLB separados para diferentes
niveles de la tabla de páginas, tal truco se vuelve innecesario.
Por lo tanto, cuando pierde el TLB, es posible no comenzar la búsqueda
desde el nivel cero (pgd *), e inmediatamente verifique el último nivel del vehículo (pte *).
No hay requisitos de hardware para mapear esta área en sí, Wirth. direcciones de
solo es necesario como índices para la búsqueda de TLB. Sin embargo, en el núcleo de
el último pgd en el nivel cero de la tabla de páginas se escribe nat. la dirección de este
nivel más cero Como resultado, solo
los últimos 4 KB del área ff80'0000'0000 - ffff'ffff'ffff - es decir justo
Nivel cero del vehículo. Esto permite que pgd * sea accesible por ordinario
leer / escribir instrucciones trabajando en direcciones virtuales.
Como resultado, se decidió simplemente poner en este registro un gran valor, que no nos molestará. Después de todo, la solución propuesta nos permite optimizar la búsqueda de páginas, pero aún no nos hemos dedicado a la optimización. Se entrega igual que en Linux.
Ahora el registro de control. Necesita habilitar MMU a través de él. Los bits conocidos se ven así:
#define _MMU_CR_TLB_EN 0x0000000000000001 #define _MMU_CR_CD_MASK 0x0000000000000006 #define _MMU_CR_SET1 0x0000000000000008 #define _MMU_CR_SET2 0x0000000000000010 #define _MMU_CR_SET3 0x0000000000000020 #define _MMU_CR_CR0_PG 0x0000000000000040 #define _MMU_CR_CR4_PSE 0x0000000000000080 #define _MMU_CR_CR0_CD 0x0000000000000100 #define _MMU_CR_TLU2_EN 0x0000000000000200 #define _MMU_CR_LD_MPT 0x0000000000000400 #define _MMU_CR_IPD_MASK 0x0000000000000800 #define _MMU_CR_UPT_EN 0x0000000000001000
Estamos interesados en el primer bit, que incluye la traducción de direcciones.
También configuramos _MMU_CR_SET3, pero no hemos descubierto en qué casos particulares se debe hacer esto.
Registro de concurso Bueno, si es simple, entonces este es el PID del proceso o espacio de direcciones. Más técnicamente, esta es una extensión de dirección de 11 bits. En nuestro caso, convertimos todas las páginas en nucleares, al establecer un poco de globalidad en todas nuestras páginas, usamos el mismo espacio de direcciones y, por lo tanto, podemos usar cero en este registro.
En el registro de la tabla raíz hay un puntero a la dirección física del comienzo de la tabla de traducción. Puede hacer un fraude asignando la tabla también a la dirección especificada en el registro MMU_REG_ELB_PTB, pero como dije, no estábamos enfocados en la optimización.
¿Qué más puedo decir? La estructura de las tablas es bastante común, las banderas son las siguientes:
#define E2K_MMU_PAGE_P 0x0000000000000001ULL #define E2K_MMU_PAGE_W 0x0000000000000002ULL #define E2K_MMU_PAGE_UU2 0x0000000000000004ULL #define E2K_MMU_PAGE_PWT 0x0000000000000008ULL #define E2K_MMU_PAGE_CD1 0x0000000000000010ULL #define E2K_MMU_PAGE_A 0x0000000000000020ULL #define E2K_MMU_PAGE_D 0x0000000000000040ULL #define E2K_MMU_PAGE_HUGE 0x0000000000000080ULL #define E2K_MMU_PAGE_G 0x0000000000000100ULL #define E2K_MMU_PAGE_CD2 0x0000000000000200ULL #define E2K_MMU_PAGE_NWA 0x0000000000000400ULL #define E2K_MMU_PAGE_AVAIL 0x0000000000000800ULL #define E2K_MMU_PAGE_PFN 0x000000fffffff000ULL #define E2K_MMU_PAGE_VALID 0x0000010000000000ULL #define E2K_MMU_PAGE_PV 0x0000020000000000ULL #define E2K_MMU_PAGE_INT_PR 0x0000040000000000ULL #define E2K_MMU_PAGE_NON_EX 0x0000080000000000ULL #define E2K_MMU_PAGE_RES 0x0000f00000000000ULL #define E2K_MMU_PAGE_C_UNIT 0xffff000000000000ULL
Para la tabla de 4 niveles, los cambios de dirección son los siguientes:
#define __MMU_PGD_SHIFT (PAGE_SHIFT + 3 * (PAGE_SHIFT-3)) #define __MMU_PUD_SHIFT (PAGE_SHIFT + 2 * (PAGE_SHIFT-3)) #define __MMU_PMD_SHIFT (PAGE_SHIFT + 1 * (PAGE_SHIFT-3))
Un poco sobre PCI
Comunicación a través de espacios de direcciones alternativos
Antes de pasar a vidyaha y tarjeta de red, regresemos brevemente a PCI. Ya hablamos un poco sobre esto en la primera parte de
"Embox comienza a escalar el Monte Elbrus" . Mostró macros para comunicarse con espacios de direcciones alternativos:
#define _E2K_READ_MAS(addr, mas, type, size_letter, chan_letter) \ ({ \ register type res; \ asm volatile ("ld" #size_letter "," #chan_letter " \t0x0, [%1] %2, %0" \ : "=r" (res) \ : "r" ((__e2k_ptr_t) (addr)), \ "i" (mas)); \ res; \ }) #define _E2K_WRITE_MAS(addr, val, mas, type, size_letter, chan_letter) \ ({ \ asm volatile ("st" #size_letter "," #chan_letter " \t0x0, [%0] %2, %1" \ : \ : "r" ((__e2k_ptr_t) (addr)), \ "r" ((type) (val)), \ "i" (mas) \ : "memory"); \ })
Y había una referencia al principio de los espacios de direcciones. Se definen diferentes espacios de direcciones utilizando el MAS (especificador de dirección de memoria). Y, por ejemplo, para acceder al IO, a través del cual se accede al PCI, debe usar 6 y MMU 7.
Pero con un estudio más exhaustivo de la macro, puede notar algún tipo de chan_letter. Y si nos fijamos en la descripción de los comandos e2k, encontramos
LDD ddd lectura de doble palabra
ldd [dirección] mas, dst
Es decir, a primera vista, no hay canales. Pero si sigue los enlaces, resulta que el código para la operación dada ldd es 67. Pero 67 es el código para ldd solo para los canales AL0 / AL3 y AL2 / AL5, y para los canales AL1 / AL4 este código corresponde a la operación POPCNTd.
Por lo tanto, no fue posible comprender completamente qué canales hay en la terminología de Elbrus. Me atrevería a sugerir que esto ya está conectado con el principio vliw, cuando puede especificar qué alu se usa, porque en este tipo de arquitectura una de las características es la presencia de varios dispositivos informáticos independientes. Puedo, por supuesto, estar equivocado, pero el hecho es que necesita usar el segundo o quinto canal para acceder a PCI o MMU. Por lo tanto, el comando se verá así:
ldd, 2 0x0, [addr_in_mas] mas_id,% reg
lspci
Ahora daré el resultado de la salida del comando lspci en el dispositivo que tenemos:
root @ embox: (nulo) #lspci
00: 0.0 (PCI dev E3E3: ABCD) [6 4]
Puente PCI a PCI: (nulo) Puente Elbrus PCIe (rev 01)
00: 1.0 (PCI dev 8086: E3E3) [6 4]
Puente PCI a PCI: puente Intel Corporation Elbrus Virt PCI (rev 01)
01: 0.0 (PCI dev 1FFF: 8000) [6 4]
Puente PCI a PCI: (nulo) Puente Elbrus PCI (rev 05)
01: 1.0 (PCI dev 8086: 4D45) [2 0]
Controlador Ethernet: Intel Corporation MCST ETH1000 Gigabit Ethernet (rev 01)
01: 2.0 (PCI dev 8086: 4D49) [1 1]
Controlador IDE: Intel Corporation MCST IDE (rev 128)
01: 2.1 (PCI dev 8086: 0002) [7 2]
Comunicación simple controlador: Intel Corporation (nulo) (rev 05)
01: 2.2 (PCI dev 8086: 8000) [7 128]
Comunicación simple Controlador: Intel Corporation Elbrus PCI bridge (rev 00)
01: 2.3 (PCI dev 1013: 6005) [4 1]
Dispositivo multimedia: Cirrus Logic Crystal CS4281 PCI Audio (rev 01)
01: 3.0 (PCI dev 8086: 4748) [1 6]
Controlador de almacenamiento masivo: Intel Corporation MCST SATA (rev 00)
01: 4.0 (PCI dev 8086: 554F) [12 3]
Dispositivo USB: Intel Corporation OHCI para Elbrus (rev 00)
01: 4.1 (PCI dev 8086: 5545) [12 3]
Dispositivo USB: Intel Corporation EHCI para Elbrus (rev 00)
02: 1.0 (PCI dev 126F: 0718) [3 0]
Controlador compatible con VGA: Silicon Motion, Inc. SM718 LynxSE + (rev 160)
root @ embox: (nulo) #
Nota
01: 2.2 (PCI dev 8086: 8000) [7 128]
Comunicación simple Controlador: Intel Corporation Elbrus PCI bridge (rev 00)
De hecho, es un puerto serie del MCST similar al am85c30, al menos a través de este dispositivo nos comunicamos a través de minicom.
Tarjeta de red
Estructura general
Ahora vamos a la tarjeta de red.
Si entiendo correctamente, esta es la tarjeta de red original, un poco similar en funcionamiento a e1000, pero solo en funcionamiento (como la presencia de descriptores en las colas de recepción y transmisión).
Ahora más sobre los puntos importantes que encontramos.
Tarjeta de red PCI VID: PID 0x8086: 0x4D45. No se sorprenda de que el VID sea el mismo que Intel, el MCST a menudo usa este VID en particular, observe al menos el dispositivo de puerto serie mencionado anteriormente.
BAR0 contiene una base de registro. Los registros son los siguientes:
#define L_E1000_E_CSR 0x00 #define L_E1000_MGIO_CSR 0x04 #define L_E1000_MGIO_DATA 0x08 #define L_E1000_E_BASE_ADDR 0x0c #define L_E1000_DMA_BASE_ADDR 0x10 #define L_E1000_PSF_CSR 0x14 #define L_E1000_PSF_DATA 0x18 #define L_E1000_INT_DELAY 0x1c
Los últimos tres (L_E1000_PSF_CSR, L_E1000_PSF_DATA, L_E1000_INT_DELAY) no los utilizamos, por lo que no hablaremos de ellos. Comencemos con MGIO, todo es simple: lectura-escritura usando el protocolo MII, es decir, comunicación con el chip PHY. Específicamente, tenemos un chip DP83865.
Los procedimientos no son particularmente notables, simplemente los enumeraré.
Lectura:
static int e1000_mii_readreg(struct net_device *dev, int phy_id, int reg_num) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t rd; uint16_t val_out = 0; int i = 0; rd = 0; rd |= 0x2 << MGIO_CS_OFF; rd |= 0x1 << MGIO_ST_OF_F_OFF; rd |= 0x2 << MGIO_OP_CODE_OFF; rd |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; rd |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; e1000_write_mgio_data(ep, rd); rd = 0; for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { rd = (uint16_t)e1000_read_mgio_data(ep); val_out = rd & 0xffff; log_debug("reg 0x%x >>> 0x%x", reg_num, val_out); return val_out; } usleep(100); } log_error("mdio_read: Unable to read from MGIO_DATA reg\n"); return val_out; }
Registro:
static void e1000_mii_writereg(struct net_device *dev, int phy_id, int reg_num, int val) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t wr; int i = 0; wr = 0; wr |= 0x2 << MGIO_CS_OFF; wr |= 0x1 << MGIO_ST_OF_F_OFF; wr |= 0x1 << MGIO_OP_CODE_OFF; wr |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; wr |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; wr |= val & 0xffff; log_debug("reg 0x%x <<< 0x%x", reg_num, val); e1000_write_mgio_data(ep, wr); for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { return; } usleep(100); } log_error("Unable to write MGIO_DATA reg: val = 0x%x", wr); return; }
Ahora L_E1000_DMA_BASE_ADDR y L_E1000_E_BASE_ADDR, de hecho, describen un parámetro, la dirección del bloque de descripción de la tarjeta de red. Es decir, la dirección en Elbrus es de 64 bits y los registros son de 32 bits.
En realidad codificar:
init_block_addr_part = (uint32_t)((uintptr_t)ep->init_block & 0xffffffff); e1000_write_e_base_addr(ep, init_block_addr_part); log_debug("Init Block Low DMA addr: 0x%x", init_block_addr_part); init_block_addr_part = (uint32_t)(((uintptr_t)(ep->init_block) >> 32) & 0xffffffff); e1000_write_dma_base_addr(ep, init_block_addr_part); log_debug("Init Block High DMA addr: 0x%x", init_block_addr_part);
De lo que se puede ver que L_E1000_DMA_BASE_ADDR es la parte superior, y L_E1000_DMA_BASE_ADDR es la parte inferior de la dirección de un determinado bloque de inicialización (en realidad un bloque de descripción de tarjeta).
La estructura de descripción es la siguiente:
struct l_e1000_init_block { uint16_t mode; uint8_t paddr[6]; uint64_t laddrf; uint32_t rdra; uint32_t tdra; } __attribute__((packed));
C laddrf - no entendí, por alguna razón se pone a cero, hicimos lo mismo.
paddr: como puede suponer, mac es la dirección de la tarjeta de red.
rdra y tdra contienen las direcciones de los anillos de los descriptores de memoria, los 4 bits inferiores se asignan al tamaño del anillo, y este es el logaritmo del tamaño. Es decir, si hay 8, entonces el número de descriptores en el anillo será 2 ^ 8 (1 << 8 == 256).
modo es el modo de la tarjeta, los bits son los siguientes:
#define DRX (1 << 0) #define DTX (1 << 1) #define LOOP (1 << 2) #define DTCR (1 << 3) #define COLL (1 << 4) #define DRTY (1 << 5) #define INTL (1 << 6) #define EMBA (1 << 7) #define EJMF (1 << 8) #define EPSF (1 << 9) #define FULL (1 << 10) #define PROM (1 << 15)
Es decir, cuando todo está configurado, debe establecer el bit 10. Si desea un modo promiscuo, entonces también 15.
Descriptores de paquetes
Ahora sobre el formato de los descriptores de paquetes.
En la recepción:
struct l_e1000_rx_desc { uint32_t base; int16_t buf_length; int16_t status; int16_t msg_length; uint16_t reserved1; uint32_t etmr; } __attribute__((packed));
base: probablemente comprenda que esta es la dirección del búfer para el paquete
buf_length - tamaño del búfer
msg_length: después de recibir, contiene la longitud del paquete recibido
estado: estado del descriptor. Cuando el paquete se prepara y se entrega a la DMA (tarjeta), debe establecer el bit 15 (RD_OWN). Si todo está bien, luego de recibir el paquete en este descriptor, este bit se restablecerá y se establecerán 9 (RD_STP) y 8 (RD_ENP).
Todos los bits de estado son los siguientes:
#define RD_OWN (1 << 15) #define RD_ERR (1 << 14) #define RD_FRAM (1 << 13) #define RD_OFLO (1 << 12) #define RD_CRC (1 << 11) #define RD_BUFF (1 << 10) #define RD_STP (1 << 9) #define RD_ENP (1 << 8) #define RD_PAM (1 << 6) #define RD_LAFM (1 << 4) #define RD_BAM (1 << 3)
En transferencia:
struct l_e1000_tx_desc { uint32_t base; int16_t buf_length; int16_t status; uint32_t misc; uint32_t etmr; } __attribute__((packed));
Casi lo mismo que recibir, los bits de estado son los siguientes:
#define TD_OWN (1 << 15) #define TD_ERR (1 << 14) #define TD_AFCS (1 << 13) #define TD_NOINTR (1 << 13) #define TD_MORE (1 << 12) #define TD_ONE (1 << 11) #define TD_DEF (1 << 10) #define TD_STP (1 << 9) #define TD_ENP (1 << 8)
Cuando se envía un paquete, es necesario establecer 15 (TD_OWN), 9 (TD_STP) y 8 (TD_ENP) en consecuencia. El bit 8 significa que este es el último paquete que se procesará, por lo tanto, si se envía un paquete, solo necesita instalarlo en el último.
También olvidé una característica importante, la longitud del búfer en los descriptores se escribe con un signo menos, probablemente en un código adicional. Incluso en little-endian, pero dado que Elbrus tiene el mismo orden de bytes, esto probablemente no sea importante.
Registro de gestión
Ahora describimos el último registro sin ensamblar L_E1000_E_CSR:
#define E_CSR_ATME (1 << 24) #define E_CSR_TMCE (1 << 23) #define E_CSR_DRIN (1 << 22) #define E_CSR_DTIN (1 << 21) #define E_CSR_ESLE (1 << 20) #define E_CSR_SLVE (1 << 19) #define E_CSR_PSFI (1 << 18) #define E_CSR_SINT (1 << 16) #define E_CSR_ERR (1 << 15) #define E_CSR_BABL (1 << 14) #define E_CSR_CERR (1 << 13) #define E_CSR_MISS (1 << 12) #define E_CSR_MERR (1 << 11) #define E_CSR_RINT (1 << 10) #define E_CSR_TINT (1 << 9) #define E_CSR_IDON (1 << 8) #define E_CSR_INTR (1 << 7) #define E_CSR_INEA (1 << 6) #define E_CSR_RXON (1 << 5) #define E_CSR_TXON (1 << 4) #define E_CSR_TDMD (1 << 3) #define E_CSR_STOP (1 << 2) #define E_CSR_STRT (1 << 1) #define E_CSR_INIT (1 << 0)
Inicialización
Hay una secuencia de inicialización algo inusual:
STOP-> INIT-> IDON-> STRT
En este caso, los bits RXON y TXON aumentan independientemente.
Más detalles se pueden encontrar en nuestro controlador.
Tarjeta de video
Como ya se señaló, nuestro dispositivo utiliza una vidyah Silicon Motion llamada SM718 LynxSE +. Por lo tanto, todo es simple, hay
fuentes de controladores en Linux y no hay nada que describir en realidad.
Bueno, excepto que el video muestra que resultó ser muy bajo en fps, se siente como un acceso lento a la memoria. Pero esto es sin la optimización del compilador, y en general, tal vez este es nuestro problema asociado con el uso incorrecto de la arquitectura e2k.
Bueno, ¿qué más decir sobre Sakhalin Elbrus?
En principio, el clima es normal :)
Aparentemente, Elbrus existe, trabaja. Personalmente, veo el principal problema del desarrollo de esta interesante arquitectura como su cercanía. Es difícil creer que una empresa relativamente pequeña pueda crear un procesador, un compilador, brindar soporte y todo lo demás. Sí, comenzaron a aparecer desarrolladores de software de terceros, el mismo Basalt-SPO es compatible con
Alt-Linux, que se puede instalar en Elbrus .
Sí, hubo informes de que desarrolladores
externos están fabricando hardware basado en el procesador Elbrus, por ejemplo
Fastwel . Pero todos estos son solo pequeños avances hacia la apertura. Un ejemplo muy simple, para reproducir lo que hemos dicho y mostrado aquí, necesitamos un compilador, y solo el
MCST lo tiene , la información proporcionada en el artículo es una adición a la información recibida de, nuevamente, el
MCST , y todavía no digo que es poco probable encontrar una pieza de hierro incluso en el MCST. Es bastante antiguo e
ICST ofrece modelos más nuevos.
PD: Naturalmente, puedes ver todo en
el repositorio de Embox .
PPS Ven al canal de telegramas ruso a través de Embox (
https://t.me/embox_chat ).
PPS Embox ha actualizado el segundo componente de la versión, ahora el actual
0.4.0