<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>BlockC Pro Ultimate - Framebuffer corregido (32/24/16/8 bits)</title>
<style>
* { box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #0a0e1a;
margin: 0;
padding: 20px;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.header {
text-align: center;
color: white;
margin-bottom: 15px;
}
.header h1 {
background: linear-gradient(135deg, #ff8c42, #ffd966);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin: 0;
}
.mode-bar {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 15px;
}
.mode-btn {
background: #1e2a36;
border: none;
padding: 6px 20px;
border-radius: 30px;
color: white;
cursor: pointer;
font-weight: bold;
}
.mode-btn.active {
background: #e67e22;
box-shadow: 0 0 8px #e67e22;
}
.main-layout {
display: flex;
gap: 15px;
flex: 1;
min-height: 0;
overflow: hidden;
}
.palette {
width: 280px;
background: #111827;
border-radius: 20px;
padding: 12px;
overflow-y: auto;
border: 1px solid #ff8c4244;
}
.palette h3 {
color: #ffd966;
margin: 12px 0 6px;
font-size: 1rem;
}
.block-tpl {
background: #f9f3d9;
border-left: 10px solid #f4b942;
border-radius: 10px;
padding: 8px 10px;
margin-bottom: 8px;
cursor: grab;
transition: 0.05s linear;
}
.block-tpl:active { cursor: grabbing; }
.block-tpl:hover { transform: translateX(3px); background: #fff3e0; }
.block-title { font-weight: bold; font-size: 0.85rem; }
.block-preview { font-family: monospace; font-size: 0.7rem; background: #e9e2c7; border-radius: 6px; padding: 2px 6px; margin-top: 3px; }
.workspace {
flex: 2;
background: #ecf0f1;
border-radius: 20px;
padding: 12px;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.workspace-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #bdc3c7;
padding-bottom: 6px;
margin-bottom: 12px;
}
.workspace-actions button {
background: #e67e22;
border: none;
color: white;
padding: 4px 12px;
border-radius: 20px;
cursor: pointer;
margin-left: 6px;
}
#blocksContainer {
display: flex;
flex-direction: column;
gap: 10px;
}
.workspace-block {
background: white;
border-radius: 14px;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: flex-start;
border-left: 8px solid #3498db;
gap: 8px;
}
.block-content {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
flex: 1;
font-family: monospace;
font-size: 0.8rem;
}
.block-label {
background: #ecf0f1;
padding: 2px 10px;
border-radius: 16px;
font-size: 0.75rem;
}
.block-input {
border: 1px solid #bdc3c7;
border-radius: 16px;
padding: 4px 10px;
font-family: monospace;
width: 130px;
}
.block-textarea {
border: 1px solid #bdc3c7;
border-radius: 12px;
padding: 4px;
font-family: monospace;
font-size: 0.7rem;
width: 180px;
resize: vertical;
}
.delete-block {
background: #e74c3c;
color: white;
border: none;
border-radius: 30px;
width: 26px;
height: 26px;
cursor: pointer;
font-weight: bold;
}
.code-panel {
width: 480px;
background: #0a0e17;
border-radius: 20px;
display: flex;
flex-direction: column;
padding: 12px;
color: #f8f8f2;
border: 1px solid #ff8c4255;
}
.code-panel h3 {
margin: 0 0 6px;
color: #f1c40f;
font-size: 1rem;
}
.code-area {
background: #000000aa;
border-radius: 14px;
padding: 10px;
font-family: 'Fira Code', monospace;
font-size: 0.7rem;
overflow: auto;
flex: 1;
white-space: pre-wrap;
}
.copy-btn, .download-btn, .hw-btn {
background: #2c7da0;
margin-top: 10px;
border: none;
padding: 6px;
border-radius: 30px;
font-weight: bold;
cursor: pointer;
color: white;
width: 100%;
}
.download-btn { background: #27ae60; }
.hw-btn { background: #8e44ad; }
.button-group {
display: flex;
gap: 8px;
}
.boot-info {
font-size: 0.65rem;
text-align: center;
margin-top: 8px;
background: #00000066;
padding: 6px;
border-radius: 12px;
}
.tab-buttons {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.tab-btn {
background: #1e2a36;
border: none;
padding: 4px 12px;
border-radius: 20px;
color: white;
cursor: pointer;
font-size: 0.75rem;
}
.tab-btn.active { background: #e67e22; }
.note {
font-size: 0.7rem;
background: #ffd96622;
padding: 4px;
border-radius: 8px;
text-align: center;
margin-top: 6px;
}
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.7);
backdrop-filter: blur(4px);
}
.modal-content {
background-color: #1e2a36;
margin: 5% auto;
padding: 20px;
border-radius: 24px;
width: 80%;
max-width: 800px;
max-height: 80vh;
overflow-y: auto;
color: #f0f0f0;
border: 1px solid #ff8c42;
}
.modal-content h2, .modal-content h3 { color: #ffd966; }
.modal-content code {
background: #0a0e1a;
padding: 3px 6px;
border-radius: 8px;
font-family: monospace;
}
.modal-content pre {
background: #0a0e1a;
padding: 10px;
border-radius: 12px;
overflow-x: auto;
font-size: 0.8rem;
}
.close {
color: #ff8c42;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover { color: #ffd966; }
.os-tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin: 15px 0;
}
.os-tab {
background: #2c3e50;
padding: 6px 12px;
border-radius: 30px;
cursor: pointer;
}
.os-tab.active { background: #e67e22; }
.os-content { display: none; }
.os-content.active { display: block; }
</style>
</head>
<body>
<div class="header">
<h1>⌨️ BlockC Pro Ultimate - Framebuffer multicorrección</h1>
<p>Soporta profundidades de color 32/24/16/8 bits, volatile y alineación Multiboot2</p>
</div>
<div class="mode-bar">
<button class="mode-btn" data-mode="linux">🐧 Modo Linux</button>
<button class="mode-btn active" data-mode="kernel">🖥️ Modo Kernel (UEFI/BIOS)</button>
</div>
<div class="main-layout">
<div class="palette">
<h3>🖥️ VGA / Framebuffer</h3>
<div class="block-tpl" draggable="true" data-block-type="vga_print"><div class="block-title">📢 Imprimir texto</div><div class="block-preview">print("texto\n");</div></div>
<div class="block-tpl" draggable="true" data-block-type="vga_clear"><div class="block-title">🧹 Limpiar pantalla</div><div class="block-preview">clear_screen();</div></div>
<div class="block-tpl" draggable="true" data-block-type="set_color"><div class="block-title">🎨 Cambiar color (VGA)</div><div class="block-preview">set_color(0x0A);</div></div>
<h3>⏱️ Delay</h3>
<div class="block-tpl" draggable="true" data-block-type="delay"><div class="block-title">⏳ Esperar (ms)</div><div class="block-preview">delay_ms(500);</div></div>
<h3>⌨️ Teclado (driver PS/2)</h3>
<div class="block-tpl" draggable="true" data-block-type="kb_getchar"><div class="block-title">🔤 Leer carácter</div><div class="block-preview">char c = keyboard_getchar();</div></div>
<div class="block-tpl" draggable="true" data-block-type="kb_wait_key"><div class="block-title">⏎ Esperar tecla</div><div class="block-preview">keyboard_wait_key();</div></div>
<div class="block-tpl" draggable="true" data-block-type="kb_have_key"><div class="block-title">📥 ¿Tecla disponible?</div><div class="block-preview">if (keyboard_have_key())</div></div>
<div class="block-tpl" draggable="true" data-block-type="kb_print_key"><div class="block-title">🔡 Mostrar tecla</div><div class="block-preview">mostrar tecla</div></div>
<div class="block-tpl" draggable="true" data-block-type="kb_check_specific"><div class="block-title">🔍 ¿Tecla específica?</div><div class="block-preview">if (last_key == 'a')</div></div>
<h3>🧠 Lógica</h3>
<div class="block-tpl" draggable="true" data-block-type="int_var"><div class="block-title">🔢 int variable</div><div class="block-preview">int x = 0;</div></div>
<div class="block-tpl" draggable="true" data-block-type="assign"><div class="block-title">✏️ Asignar</div><div class="block-preview">x = 42;</div></div>
<div class="block-tpl" draggable="true" data-block-type="if_stmt"><div class="block-title">⚖️ if</div><div class="block-preview">if (x > 0) { }</div></div>
<div class="block-tpl" draggable="true" data-block-type="while_loop"><div class="block-title">🔄 while</div><div class="block-preview">while (cond) { }</div></div>
<div class="block-tpl" draggable="true" data-block-type="for_loop"><div class="block-title">🔁 for</div><div class="block-preview">for(...)</div></div>
<h3>🔌 Puerto serie</h3>
<div class="block-tpl" draggable="true" data-block-type="serial_put"><div class="block-title">📡 Imprimir por serie</div><div class="block-preview">serial_print("debug\n");</div></div>
</div>
<div class="workspace">
<div class="workspace-header">
<h3>🧩 Tus bloques</h3>
<div class="workspace-actions">
<button id="clearBtn">🗑️ Limpiar</button>
<button id="demoKernelVga">🎮 Demo: Mini consola</button>
<button id="demoLinesBtn">📝 Demo: Saltos de línea</button>
<button id="hwManualBtn" style="background:#8e44ad;">💿 ISO híbrida (UEFI+BIOS)</button>
</div>
</div>
<div id="blocksContainer"></div>
<div class="note">💡 Escribe en los campos sin perder foco. El kernel ahora soporta cualquier profundidad de color.</div>
</div>
<div class="code-panel">
<div class="tab-buttons">
<button class="tab-btn active" data-tab="c">📄 kernel.c</button>
<button class="tab-btn" data-tab="asm">⚙️ boot.asm</button>
</div>
<div class="code-area" id="codeArea"></div>
<div class="button-group">
<button id="copyBtn" class="copy-btn">📋 Copiar código</button>
<button id="downloadBtn" class="download-btn">💾 Descargar kernel.c</button>
</div>
<div class="boot-info" id="bootInfo"></div>
</div>
</div>
<div id="hwModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h2>💿 Crear ISO híbrida (UEFI + BIOS)</h2>
<p>Instrucciones actualizadas con modo de color 32 bits para framebuffer.</p>
<div class="os-tabs">
<div class="os-tab active" data-os="debian">🐧 Debian/Ubuntu</div>
<div class="os-tab" data-os="arch">🎯 Arch Linux</div>
<div class="os-tab" data-os="alpine">🗻 Alpine</div>
<div class="os-tab" data-os="windows">🪟 Windows (WSL)</div>
</div>
<div id="os-debian" class="os-content active">
<pre><code># Instalar herramientas
sudo apt update
sudo apt install nasm gcc-multilib xorriso grub-pc-bin grub-efi-amd64-bin
# Compilar
nasm -f elf32 boot.asm -o boot.o
gcc -ffreestanding -nostdlib -m32 -fno-stack-protector -c kernel.c -o kernel.o
ld -m elf_i386 -Ttext 0x100000 boot.o kernel.o -o kernel.elf
# Crear estructura ISO
mkdir -p iso/boot/grub/fonts
cp kernel.elf iso/boot/
cp /usr/share/grub/unicode.pf2 iso/boot/grub/fonts/ 2>/dev/null || echo "Fuente no encontrada, continuar sin ella"
# grub.cfg con resolución y profundidad 32 bits
cat > iso/boot/grub/grub.cfg << "EOF"
set gfxmode=1024x768x32,auto
set gfxpayload=keep
insmod efi_gop
insmod efi_uga
insmod vbe
insmod font
if loadfont ${prefix}/fonts/unicode.pf2; then
set gfxmode=auto
set gfxpayload=keep
terminal_output gfxterm
fi
set timeout=3
set default=0
menuentry "BlockC Kernel" {
multiboot2 /boot/kernel.elf
boot
}
EOF
# Generar ISO híbrida
grub-mkrescue -o blockc.iso iso/
# Probar en QEMU (BIOS)
qemu-system-x86_64 -cdrom blockc.iso -serial stdio
# Probar en QEMU (UEFI)
qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -cdrom blockc.iso -serial stdio
# Grabar en USB (cuidado con el dispositivo)
sudo dd if=blockc.iso of=/dev/sdX bs=4M status=progress</code></pre>
</div>
<div id="os-arch" class="os-content"><pre><code>sudo pacman -S nasm gcc-multilib xorriso grub
# Mismos comandos de compilación y copia de fuente</code></pre></div>
<div id="os-alpine" class="os-content"><pre><code>apk add nasm gcc-multilib xorriso grub</code></pre></div>
<div id="os-windows" class="os-content"><pre><code>Usa WSL (Ubuntu) y sigue pasos de Debian.</code></pre></div>
<p><strong>✅ La ISO ahora fuerza modo 32 bits, eliminando errores de escritura en profundidades incompatibles.</strong></p>
</div>
</div>
<script>
let blocks = [];
let nextId = 1;
let currentMode = "kernel";
let currentTab = "c";
// boot.asm MULTIBOOT2 completo (igual que antes, funciona correctamente)
const BOOT_ASM = `[bits 32]
section .text
align 8
dd 0xE85250D6
dd 0x00
dd (header_end - header_start)
dd -(0xE85250D6 + 0x00 + (header_end - header_start))
header_start:
align 8
dw 5, 0
dd 20
dd 0, 0, 0
align 8
dw 0, 0
dd 8
header_end:
global _start
extern kernel_main
_start:
cli
mov esp, stack_space
push ebx
push eax
call kernel_main
hlt
section .bss
resb 8192
stack_space:`;
// Persistencia, descarga, escape
function saveProject() { localStorage.setItem("blockc_project", JSON.stringify(blocks)); }
function loadProject() {
const data = localStorage.getItem("blockc_project");
if (data) {
blocks = JSON.parse(data);
if (blocks.length) nextId = Math.max(...blocks.map(b=>b.id)) + 1;
}
}
function downloadFile(name, content) {
const a = document.createElement("a");
const blob = new Blob([content], { type: "text/plain" });
a.href = URL.createObjectURL(blob);
a.download = name;
a.click();
URL.revokeObjectURL(a.href);
}
function escapeForC(str) {
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t');
}
function blockDataTemplate(type) {
if (type === 'vga_print') return { text: "Hola mundo", color: "0x07" };
if (type === 'vga_clear') return {};
if (type === 'set_color') return { color: "0x0A" };
if (type === 'delay') return { millis: "500" };
if (type === 'kb_getchar') return { var_name: "c" };
if (type === 'kb_wait_key') return {};
if (type === 'kb_have_key') return {};
if (type === 'kb_print_key') return {};
if (type === 'kb_check_specific') return { key: "a" };
if (type === 'int_var') return { var_name: "x", init_val: "0" };
if (type === 'assign') return { var_name: "x", value: "42" };
if (type === 'if_stmt') return { condition: "x > 0", body: " // acción" };
if (type === 'while_loop') return { condition: "1", body: " // bucle" };
if (type === 'for_loop') return { init: "int i=0", cond: "i<5", inc: "i++", body: " print(\"i\");" };
if (type === 'serial_put') return { text: "debug\\r\\n" };
return {};
}
function blockToLines(block) {
const t = block.type;
const d = block.data;
if (t === 'vga_print') return [`print("${escapeForC(d.text)}");`];
if (t === 'vga_clear') return [`clear_screen();`];
if (t === 'set_color') return [`set_color(${d.color});`];
if (t === 'delay') return [`delay_ms(${d.millis});`];
if (t === 'kb_getchar') return [`char ${d.var_name} = keyboard_getchar();`];
if (t === 'kb_wait_key') return [`keyboard_wait_key();`];
if (t === 'kb_have_key') return [`if (keyboard_have_key()) {`, ` // tecla disponible`, `}`];
if (t === 'kb_print_key') return [`char key = keyboard_getchar();`, `print_char(key);`];
if (t === 'kb_check_specific') return [`if (last_key == '${d.key}') {`, ` print("Tecla detectada!");`, `}`];
if (t === 'int_var') return [`int ${d.var_name} = ${d.init_val};`];
if (t === 'assign') return [`${d.var_name} = ${d.value};`];
if (t === 'if_stmt') return [`if (${d.condition}) {`, ` ${d.body.replace(/\n/g, '\n ')}`, `}`];
if (t === 'while_loop') return [`while (${d.condition}) {`, ` ${d.body.replace(/\n/g, '\n ')}`, `}`];
if (t === 'for_loop') return [`for (${d.init}; ${d.cond}; ${d.inc}) {`, ` ${d.body.replace(/\n/g, '\n ')}`, `}`];
if (t === 'serial_put') return [`serial_print("${escapeForC(d.text)}");`];
return [`/* ${t} */`];
}
function needsKeyboard() {
return blocks.some(b => ['kb_getchar','kb_wait_key','kb_have_key','kb_print_key','kb_check_specific'].includes(b.type));
}
// GENERADOR DE KERNEL.C CORREGIDO
function generateKernelC() {
let lines = [];
lines.push("// kernel.c - Framebuffer con soporte de profundidad variable, volatile, alineación Multiboot2");
lines.push("#include <stdint.h>");
lines.push("");
lines.push("// ---------- Puertos serie (debug) ----------");
lines.push("#define COM1 0x3f8");
lines.push("static inline void outb(uint16_t port, uint8_t val) { asm volatile(\"outb %0, %1\" : : \"a\"(val), \"Nd\"(port)); }");
lines.push("static inline uint8_t inb(uint16_t port) { uint8_t ret; asm volatile(\"inb %1, %0\" : \"=a\"(ret) : \"Nd\"(port)); return ret; }");
lines.push("static void serial_putchar(char c) { while(!(inb(COM1+5)&0x20)); outb(COM1,c); }");
lines.push("void serial_print(const char *s) { while(*s) serial_putchar(*s++); }");
lines.push("");
lines.push("// ---------- Framebuffer con soporte de profundidad ----------");
lines.push("static volatile uint32_t* fb_addr = 0; // volatile para evitar optimización");
lines.push("static volatile uint32_t fb_width = 0, fb_height = 0, fb_pitch = 0;");
lines.push("static volatile uint8_t fb_bpp = 0;");
lines.push("static volatile int fb_enabled = 0;");
lines.push("static int fb_cursor_x = 0, fb_cursor_y = 0;");
lines.push("");
lines.push("// Escribe un píxel con color (RGB, dependiendo de la profundidad)");
lines.push("static void fb_put_pixel(uint32_t x, uint32_t y, uint32_t color) {");
lines.push(" if (!fb_addr || x >= fb_width || y >= fb_height) return;");
lines.push(" uint8_t* ptr = (uint8_t*)fb_addr + y * fb_pitch + x * (fb_bpp/8);");
lines.push(" switch(fb_bpp) {");
lines.push(" case 32: *(uint32_t*)ptr = color; break;");
lines.push(" case 24: ptr[0] = (color>>16)&0xFF; ptr[1] = (color>>8)&0xFF; ptr[2] = color&0xFF; break;");
lines.push(" case 16: {");
lines.push(" uint16_t c16 = ((color>>19)&0x1F)<<11 | ((color>>10)&0x3F)<<5 | ((color>>3)&0x1F);");
lines.push(" *(uint16_t*)ptr = c16;");
lines.push(" break;");
lines.push(" }");
lines.push(" case 8: *ptr = (color>>16)&0xFF; break;");
lines.push(" default: break;");
lines.push(" }");
lines.push("}");
lines.push("");
lines.push("// Dibuja un carácter (8x16) usando el color dado");
lines.push("static void fb_putchar(char c, uint32_t color) {");
lines.push(" (void)c; // por simplicidad dibujamos un cuadrado de color");
lines.push(" for (int py = 0; py < 16; py++)");
lines.push(" for (int px = 0; px < 8; px++) {");
lines.push(" uint32_t x = fb_cursor_x*8 + px;");
lines.push(" uint32_t y = fb_cursor_y*16 + py;");
lines.push(" if (x < fb_width && y < fb_height)");
lines.push(" fb_put_pixel(x, y, color);");
lines.push(" }");
lines.push(" fb_cursor_x++;");
lines.push(" if (fb_cursor_x >= fb_width/8) { fb_cursor_x = 0; fb_cursor_y++; }");
lines.push("}");
lines.push("");
lines.push("// ---------- VGA modo texto (fallback) ----------");
lines.push("static char* const VGA_MEM = (char*)0xB8000;");
lines.push("static int vga_x = 0, vga_y = 0;");
lines.push("static uint8_t vga_color = 0x07;");
lines.push("");
lines.push("static void vga_scroll(void) {");
lines.push(" for (int y = 1; y < 25; y++)");
lines.push(" for (int x = 0; x < 80; x++) {");
lines.push(" int from = (y*80+x)*2, to = ((y-1)*80+x)*2;");
lines.push(" VGA_MEM[to] = VGA_MEM[from]; VGA_MEM[to+1] = VGA_MEM[from+1];");
lines.push(" }");
lines.push(" for (int x = 0; x < 80; x++) {");
lines.push(" int pos = (24*80+x)*2;");
lines.push(" VGA_MEM[pos] = ' '; VGA_MEM[pos+1] = vga_color;");
lines.push(" }");
lines.push(" vga_y = 24;");
lines.push("}");
lines.push("");
lines.push("static void vga_putchar(char c) {");
lines.push(" if (c == 8) {");
lines.push(" if (vga_x > 0) vga_x--;");
lines.push(" int pos = (vga_y*80+vga_x)*2;");
lines.push(" VGA_MEM[pos] = ' '; VGA_MEM[pos+1] = vga_color;");
lines.push(" return;");
lines.push(" }");
lines.push(" if (c == '\\n') { vga_x = 0; vga_y++; }");
lines.push(" else {");
lines.push(" int pos = (vga_y*80+vga_x)*2;");
lines.push(" VGA_MEM[pos] = c; VGA_MEM[pos+1] = vga_color;");
lines.push(" vga_x++;");
lines.push(" if (vga_x >= 80) { vga_x = 0; vga_y++; }");
lines.push(" }");
lines.push(" if (vga_y >= 25) vga_scroll();");
lines.push("}");
lines.push("");
lines.push("void set_color(uint8_t color) { vga_color = color; }");
lines.push("");
lines.push("void clear_screen() {");
lines.push(" if (fb_enabled && fb_addr) {");
lines.push(" for (uint32_t y = 0; y < fb_height; y++)");
lines.push(" for (uint32_t x = 0; x < fb_width; x++)");
lines.push(" fb_put_pixel(x, y, 0x00000000);");
lines.push(" fb_cursor_x = fb_cursor_y = 0;");
lines.push(" serial_print(\"Framebuffer limpiado (\");");
lines.push(" serial_print((fb_bpp==32?\"32\":fb_bpp==24?\"24\":fb_bpp==16?\"16\":\"8\"));");
lines.push(" serial_print(\" bpp)\\r\\n\");");
lines.push(" } else {");
lines.push(" for (int i = 0; i < 80*25; i++) { VGA_MEM[i*2] = ' '; VGA_MEM[i*2+1] = vga_color; }");
lines.push(" vga_x = vga_y = 0;");
lines.push(" serial_print(\"VGA limpiado\\r\\n\");");
lines.push(" }");
lines.push("}");
lines.push("");
lines.push("void print_char(char c) {");
lines.push(" if (fb_enabled && fb_addr) fb_putchar(c, 0x00FFFFFF);");
lines.push(" else vga_putchar(c);");
lines.push("}");
lines.push("");
lines.push("void print(const char *s) { while(*s) print_char(*s++); }");
lines.push("");
lines.push("// ---------- Delay ----------");
lines.push("static void delay_cycles(int count) { for(volatile int i=0;i<count;i++) asm volatile(\"nop\"); }");
lines.push("void delay_ms(int ms) { for(int i=0;i<ms;i++) delay_cycles(2000); }");
lines.push("");
lines.push("// ---------- Teclado (opcional) ----------");
if (needsKeyboard()) {
lines.push("#define KEYBOARD_DATA 0x60");
lines.push("#define KEYBOARD_STATUS 0x64");
lines.push("static char last_key = 0;");
lines.push("static int shift_pressed = 0;");
lines.push("static const char keymap[128] = {");
lines.push("0,27,'1','2','3','4','5','6','7','8','9','0','-','=',8,9,");
lines.push("'q','w','e','r','t','y','u','i','o','p','[',']',13,0,'a','s',");
lines.push("'d','f','g','h','j','k','l',';','\\'','`',0,'\\\\','z','x','c','v',");
lines.push("'b','n','m',',','.','/',0,'*',0,' ',0};");
lines.push("static uint8_t keyboard_read_scancode(void) { while(!(inb(KEYBOARD_STATUS)&1)); return inb(KEYBOARD_DATA); }");
lines.push("char keyboard_getchar(void) {");
lines.push(" uint8_t sc;");
lines.push(" while(1) {");
lines.push(" sc = keyboard_read_scancode();");
lines.push(" if(sc == 0x2A || sc == 0x36) { shift_pressed = 1; continue; }");
lines.push(" if(sc == 0xAA || sc == 0xB6) { shift_pressed = 0; continue; }");
lines.push(" if(sc & 0x80) continue;");
lines.push(" char c = keymap[sc];");
lines.push(" if(c) { last_key = c; return c; }");
lines.push(" }");
lines.push("}");
lines.push("int keyboard_have_key(void) { return (inb(KEYBOARD_STATUS) & 1); }");
lines.push("void keyboard_wait_key(void) { keyboard_getchar(); }");
}
lines.push("");
lines.push("// ---------- Parseo Multiboot2 con alineación correcta ----------");
lines.push("struct multiboot_tag { uint32_t type; uint32_t size; };");
lines.push("struct multiboot_tag_fb {");
lines.push(" uint32_t type; uint32_t size; uint64_t addr;");
lines.push(" uint32_t pitch; uint32_t width; uint32_t height;");
lines.push(" uint8_t bpp; uint8_t type_fb;");
lines.push("};");
lines.push("");
lines.push("static void multiboot2_init(unsigned long magic, unsigned long addr) {");
lines.push(" serial_print(\"multiboot2_init\\r\\n\");");
lines.push(" if (magic != 0x36d76289) { serial_print(\"Magic incorrecto\\r\\n\"); return; }");
lines.push(" if (!addr) { serial_print(\"Puntero nulo\\r\\n\"); return; }");
lines.push(" uint32_t* tags = (uint32_t*)addr;");
lines.push(" while (1) {");
lines.push(" uint32_t type = tags[0];");
lines.push(" uint32_t size = tags[1];");
lines.push(" if (type == 0) break;");
lines.push(" if (type == 8) {");
lines.push(" struct multiboot_tag_fb* fb = (struct multiboot_tag_fb*)tags;");
lines.push(" if (fb->addr && fb->width && fb->height) {");
lines.push(" fb_addr = (uint32_t*)(uintptr_t)fb->addr;");
lines.push(" fb_width = fb->width;");
lines.push(" fb_height = fb->height;");
lines.push(" fb_pitch = fb->pitch;");
lines.push(" fb_bpp = fb->bpp;");
lines.push(" fb_enabled = 1;");
lines.push(" serial_print(\"Framebuffer detectado \");");
lines.push(" serial_print((fb_bpp==32?\"32\":fb_bpp==24?\"24\":fb_bpp==16?\"16\":\"8\"));");
lines.push(" serial_print(\" bpp\\r\\n\");");
lines.push(" }");
lines.push(" }");
lines.push(" // Alineación a 8 bytes según especificación Multiboot2");
lines.push(" size = (size + 7) & ~7;");
lines.push(" tags = (uint32_t*)((char*)tags + size);");
lines.push(" }");
lines.push("}");
lines.push("");
lines.push("void kernel_main(unsigned long magic, unsigned long addr) {");
lines.push(" serial_print(\"Kernel_main\\r\\n\");");
lines.push(" multiboot2_init(magic, addr);");
lines.push(" clear_screen();");
lines.push(" print(\"BlockC Pro Ultimate\\n\");");
lines.push(" print(\"Framebuffer + VGA\\n\");");
for (let blk of blocks) {
let blines = blockToLines(blk);
for (let l of blines) lines.push(" " + l);
}
const hasInfiniteLoop = blocks.some(b => b.type === 'while_loop' && b.data.condition.trim() === "1");
if (!hasInfiniteLoop) lines.push(" while(1);");
lines.push("}");
return lines.join("\n");
}
function updateDisplay() {
const area = document.getElementById('codeArea');
if (currentTab === 'c') area.innerText = generateKernelC();
else area.innerText = BOOT_ASM;
const infoDiv = document.getElementById('bootInfo');
if (currentMode === 'kernel') {
infoDiv.innerHTML = `🔧 Compilar y crear ISO híbrida con modo color 32 bits:<br>
nasm -f elf32 boot.asm -o boot.o<br>
gcc -ffreestanding -nostdlib -m32 -fno-stack-protector -c kernel.c -o kernel.o<br>
ld -m elf_i386 -Ttext 0x100000 boot.o kernel.o -o kernel.elf<br>
mkdir -p iso/boot/grub/fonts<br>
cp kernel.elf iso/boot/<br>
cp /usr/share/grub/unicode.pf2 iso/boot/grub/fonts/ 2>/dev/null<br>
(seguir el manual para grub.cfg)<br>
grub-mkrescue -o blockc.iso iso/`;
} else {
infoDiv.innerHTML = `🐧 Modo Linux: gcc kernel.c -o kernel && ./kernel (solo simula)`;
}
}
function refreshCodeAndSave() { updateDisplay(); saveProject(); }
function renderWorkspace() {
const container = document.getElementById('blocksContainer');
container.innerHTML = '';
for (let block of blocks) {
const div = document.createElement('div');
div.className = 'workspace-block';
const contentDiv = document.createElement('div');
contentDiv.className = 'block-content';
const t = block.type;
const d = block.data;
if (t === 'vga_print') {
contentDiv.appendChild(labelSpan("print:"));
const ta = document.createElement('textarea');
ta.className = 'block-textarea';
ta.value = d.text;
ta.rows = 2;
ta.addEventListener('input', e => { d.text = e.target.value; refreshCodeAndSave(); });
contentDiv.appendChild(ta);
contentDiv.appendChild(labelSpan("color (VGA):"));
const inp = createInputNoRender(d.color, v=>{ d.color=v; refreshCodeAndSave(); }, "0x07");
contentDiv.appendChild(inp);
} else if (t === 'vga_clear') {
contentDiv.appendChild(labelSpan("clear_screen()"));
} else if (t === 'set_color') {
contentDiv.appendChild(labelSpan("set_color("));
contentDiv.appendChild(createInputNoRender(d.color, v=>{ d.color=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(")"));
} else if (t === 'delay') {
contentDiv.appendChild(labelSpan("delay_ms("));
contentDiv.appendChild(createInputNoRender(d.millis, v=>{ d.millis=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(")"));
} else if (t === 'kb_getchar') {
contentDiv.appendChild(labelSpan("char"));
contentDiv.appendChild(createInputNoRender(d.var_name, v=>{ d.var_name=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan("= keyboard_getchar()"));
} else if (t === 'kb_wait_key') {
contentDiv.appendChild(labelSpan("keyboard_wait_key()"));
} else if (t === 'kb_have_key') {
contentDiv.appendChild(labelSpan("if (keyboard_have_key())"));
} else if (t === 'kb_print_key') {
contentDiv.appendChild(labelSpan("Mostrar tecla"));
} else if (t === 'kb_check_specific') {
contentDiv.appendChild(labelSpan("if tecla == "));
contentDiv.appendChild(createInputNoRender(d.key, v=>{ d.key=v; refreshCodeAndSave(); }));
} else if (t === 'int_var') {
contentDiv.appendChild(labelSpan("int"));
contentDiv.appendChild(createInputNoRender(d.var_name, v=>{ d.var_name=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan("="));
contentDiv.appendChild(createInputNoRender(d.init_val, v=>{ d.init_val=v; refreshCodeAndSave(); }));
} else if (t === 'assign') {
contentDiv.appendChild(createInputNoRender(d.var_name, v=>{ d.var_name=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan("="));
contentDiv.appendChild(createInputNoRender(d.value, v=>{ d.value=v; refreshCodeAndSave(); }));
} else if (t === 'if_stmt') {
contentDiv.appendChild(labelSpan("if ("));
contentDiv.appendChild(createInputNoRender(d.condition, v=>{ d.condition=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(") {"));
const ta = createTextareaNoRender(d.body, v=>{ d.body=v; refreshCodeAndSave(); });
contentDiv.appendChild(ta);
} else if (t === 'while_loop') {
contentDiv.appendChild(labelSpan("while ("));
contentDiv.appendChild(createInputNoRender(d.condition, v=>{ d.condition=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(") {"));
const ta = createTextareaNoRender(d.body, v=>{ d.body=v; refreshCodeAndSave(); });
contentDiv.appendChild(ta);
} else if (t === 'for_loop') {
contentDiv.appendChild(labelSpan("for ("));
contentDiv.appendChild(createInputNoRender(d.init, v=>{ d.init=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(";"));
contentDiv.appendChild(createInputNoRender(d.cond, v=>{ d.cond=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(";"));
contentDiv.appendChild(createInputNoRender(d.inc, v=>{ d.inc=v; refreshCodeAndSave(); }));
contentDiv.appendChild(labelSpan(") {"));
const ta = createTextareaNoRender(d.body, v=>{ d.body=v; refreshCodeAndSave(); });
contentDiv.appendChild(ta);
} else if (t === 'serial_put') {
contentDiv.appendChild(labelSpan("serial_print:"));
const ta = document.createElement('textarea');
ta.className = 'block-textarea';
ta.value = d.text;
ta.rows = 2;
ta.addEventListener('input', e => { d.text = e.target.value; refreshCodeAndSave(); });
contentDiv.appendChild(ta);
}
const del = document.createElement('button');
del.innerText = '✖';
del.className = 'delete-block';
del.onclick = () => { blocks = blocks.filter(b=>b.id!==block.id); renderWorkspace(); updateDisplay(); saveProject(); };
div.appendChild(contentDiv);
div.appendChild(del);
container.appendChild(div);
}
updateDisplay();
saveProject();
}
function labelSpan(t) { let s = document.createElement('span'); s.className = 'block-label'; s.innerText = t; return s; }
function createInputNoRender(val, onChange, ph="") {
let inp = document.createElement('input');
inp.className = 'block-input';
inp.value = val;
inp.placeholder = ph;
inp.addEventListener('input', e => onChange(e.target.value));
return inp;
}
function createTextareaNoRender(val, onChange) {
let ta = document.createElement('textarea');
ta.className = 'block-textarea';
ta.value = val;
ta.rows = 2;
ta.addEventListener('input', e => onChange(e.target.value));
return ta;
}
function addBlock(type) {
blocks.push({ id: nextId++, type: type, data: blockDataTemplate(type) });
renderWorkspace();
}
// Drag & Drop
document.querySelectorAll('.block-tpl').forEach(el => {
el.setAttribute('draggable', 'true');
el.addEventListener('dragstart', e => e.dataTransfer.setData('text/plain', el.getAttribute('data-block-type')));
});
document.querySelector('.workspace').addEventListener('dragover', e => e.preventDefault());
document.querySelector('.workspace').addEventListener('drop', e => {
e.preventDefault();
const type = e.dataTransfer.getData('text/plain');
if (type) addBlock(type);
});
// Modo Linux/Kernel
document.querySelectorAll('.mode-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.mode-btn').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
currentMode = btn.getAttribute('data-mode');
updateDisplay();
});
});
// Tabs
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
currentTab = btn.getAttribute('data-tab');
updateDisplay();
});
});
document.getElementById('clearBtn').onclick = () => { blocks = []; renderWorkspace(); };
document.getElementById('demoKernelVga').onclick = () => {
blocks = [];
addBlock('vga_clear');
addBlock('vga_print');
addBlock('while_loop');
setTimeout(() => {
if(blocks[1]) { blocks[1].data.text = "=== Mini Consola BlockC ===\nEscribe y presiona Enter...\n> "; }
if(blocks[2]) {
blocks[2].data.condition = "1";
blocks[2].data.body = `char c = keyboard_getchar();
if(c == '\\n') print("\\n> ");
else print_char(c);`;
}
renderWorkspace();
},10);
};
document.getElementById('demoLinesBtn').onclick = () => {
blocks = [];
addBlock('vga_clear');
addBlock('vga_print');
addBlock('vga_print');
addBlock('vga_print');
setTimeout(() => {
if(blocks[1]) { blocks[1].data.text = "¡Hola!\nEsto es una línea nueva.\n"; }
if(blocks[2]) { blocks[2].data.text = "Y aquí otra línea.\n"; }
if(blocks[3]) { blocks[3].data.text = "Usa \\n en tus textos.\n¡Disfruta BlockC!"; }
renderWorkspace();
},10);
};
document.getElementById('copyBtn').onclick = () => {
let content = (currentTab === 'c') ? generateKernelC() : BOOT_ASM;
navigator.clipboard.writeText(content);
alert("✅ Código copiado");
};
document.getElementById('downloadBtn').onclick = () => {
let content = generateKernelC();
downloadFile("kernel.c", content);
};
// Modal manual
const modal = document.getElementById('hwModal');
const hwBtn = document.getElementById('hwManualBtn');
const spanClose = document.getElementsByClassName('close')[0];
hwBtn.onclick = () => modal.style.display = "block";
spanClose.onclick = () => modal.style.display = "none";
window.onclick = (event) => { if(event.target == modal) modal.style.display = "none"; };
document.querySelectorAll('.os-tab').forEach(tab => {
tab.addEventListener('click', () => {
const os = tab.getAttribute('data-os');
document.querySelectorAll('.os-tab').forEach(t=>t.classList.remove('active'));
tab.classList.add('active');
document.querySelectorAll('.os-content').forEach(c=>c.classList.remove('active'));
document.getElementById(`os-${os}`).classList.add('active');
});
});
// Inicializar
loadProject();
if (blocks.length === 0) {
addBlock('vga_print');
setTimeout(() => { if(blocks[0]) { blocks[0].data.text = "BlockC Pro Ultimate\nArranca en UEFI/BIOS con framebuffer 32/24/16/8 bits"; } renderWorkspace(); },10);
} else renderWorkspace();
</script>
</body>
</html>
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)