samsaga2
|
|
« : 09 de Noviembre de 2011, 05:15:50 pm » |
|
Como me sobra tanto tiempo libre y siguiendo la moda de abandonar la scene emesexera (o no) he retomado un proyecto que tenía perdido por el disco duro y lo he subido a github: https://github.com/samsaga2/Z80-IR-CompilerMe le explico (explicomele para los amigos). ¿Os gustaría tener éste código en basic... REM test 10 a = &h1 ' com 1 20 b = &b10: c = 3 : d = a+b+c ' com 2
...compilarlo y obtener... ; main _main: ld bc,&h1 ld [_a],bc ld bc,&b10 ld [_b],bc ld bc,3 ld [_c],bc ld de,[_a] ld hl,[_b] add hl,de ld de,hl ld hl,[_c] add hl,de ld bc,hl ld [_d],bc ret
o este codigo en pseudo-c# int test1() { return 0x1; }
int test2() { return 0b10+3; }
int test3() { return test1() + test2(); }
int test4() { int a=test1(); int b=test2(); int c=a+b; return c+test3(); }
...y obtener... ; test1 _test1: ld hl,0x1 ret
; test2 _test2: ld hl,(3+0b10) ret
; test3 _test3: call _test1 ld de,hl call _test2 add hl,de ret
; test4 _test4: call _test1 ld de,hl call _test2 add hl,de push hl call _test3 pop de add hl,de ret
Pues ahora gracias a meloflipo productions podeis. Bueno, podeis si os interesa programar sin agrumentos, ni condicionales ni bucles ni nada y sólo pudiendo sumar (esto está en pañalísimos). Leer el TODO.txt para haceros un idea de lo que falta, que es todo. Pero la parte más complicada, el register allocator, está hecha (estilo ssa que es la técnica mas avanzada). Mi idea es hacer una especie de .Net pero con cross-compiling (y sin garbage colector). Soportando un pseudo lenguaje parecido a c# y otro para basic lo más compatible posible con el de msx. Lo he hecho básicamente para aprender a hacer compiladores. Pero dependiendo de lo que me anime la gente lo continuaré o no.
|
|
|
En línea
|
|
|
|
aorante
|
|
« Respuesta #1 : 10 de Noviembre de 2011, 03:00:13 pm » |
|
Me parece muy interesante tu proyecto.
Creo que ya se hablo de algo parecido en estos foros, relacionado con java.
Yo sugería hacer un lenguaje con una sintaxis similar al java-script (muy parecida a la de java y C#). Creo que hay mucha gente que conoce estos lenguajes y le seria más sencillo meterse a la programación para MSX.
El problema es que debe de ser complicado o costoso, sobre todo si se quiere obtener un resultado optimo. Es una de las razones por las que se trabaja más directamente en assembler que con otros lenguajes como el C.
Por cierto, ¿donde esta el fichero Todo.txt?
Saludos!
|
|
|
En línea
|
|
|
|
|
Jos'b
|
|
« Respuesta #3 : 11 de Noviembre de 2011, 09:55:08 am » |
|
A mi me parece un proyecto interesante, ojalá podamos ver el resultado final.
|
|
|
En línea
|
|
|
|
Mortimer
|
|
« Respuesta #4 : 11 de Noviembre de 2011, 10:11:36 am » |
|
Tiene muy buena pinta ! Yo pensé hacer algo parecido en Java (No sé si será a lo que se refiere aorante), pero más pensado para RAD y bocetos en PC que un compilador fina para Z80. Es decir programabas en Java con unas funciones para acceder a los recursos de un MSX que funcionaría en el emulador (Tomando atajos), pero sin el paso de compilar a Z80 para poder usarse en un máquina real.
|
|
|
En línea
|
|
|
|
aorante
|
|
« Respuesta #5 : 11 de Noviembre de 2011, 06:05:55 pm » |
|
Una idea: Al lenguaje le añadiría unos objetos (creo que similar a como funcionan los widgets de macOS), para acceder el hardware y facilitar la vida al programador. Te mando un ejemplo de como podría ser. Espero que te sirva. Muchos podrían ser sustituidos por llamadas a la BIOS, aunque eso implicaría a que el resultado fuera una ROM. void prueba() { // definicion de variables var data = new Array(100,110,110,100,44,44,32,32); byte position; byte value; byte A; // 8 bits int HL; // 16 bits boolean trigger=false; A++; // autoincremento A--; value = sys.msx.gen; //variable de sistema, proporciona el codigo de generacion de MSX //value = sys.ram.size; vdp.screen.setMode(2); // inicializa el modo de pantalla value = vdp.screen.mode; // lee el modo de pantalla vdp.sprite.setMode(1); // inicializa el modo de sprites: 0=8x8; 1=16x16 vdp.sprite.zoom = false; // activa el modo zoom de los sprites vdp.vram.writeBlock(0x3800,data); // escribe un bloque de datos en la VRAM vdp.vram.poke(0x1B01,20); // escribe un byte en la VRAM value = vdp.vram.peek(0x1B01); // lee un byte de la VRAM // funciones que actuan directamente con la tabla de nombre de patrones vdp.tile.set(x,y,value); value = vdp.tile.get(x,y); // funciones para imprimir texto en la pantalla // actuan directamente con la tabla de nombre de patrones // validas incluso para screen2 // Nota: la ultima posición se guarda en una variable de sistema vdp.locate(x,y); // base(0)+(y*32)+x con base 5 para sc1 o 10 para sc2 vdp.print(cadena); //accede a los registros del vdp vdp.set(0,12); value = vdp.get(0); // acceso a los atributos de los sprites // idea: funcion para definir sprite vdp.sprite.setPlane(0,1); // asigna un sprite a un plano de pantalla vdp.sprite.setPosition(1,100,120); // (num plano, x,y) vdp.sprite.setColor(1,15); // (num plano, color) vdp.sprite.visible(1) = false; // (num plano) posiciona el sprite y=209 // haciendolo oculto // acceso al PSG psg.channelA.volume = 15; psg.channelA.frequency = 1500; psg.channelA.tone = true; psg.channelA.noise = false; // idem para B y C psg.noise.period = 31; psg.envelope.period =1000; psg.envelope.wave = 1; // acceso a la RAM sys.ram.poke(1000,10); value = sys.ram.peek(1000); // acceso al teclado value = ppi.key(0); //num de fila // acceso a los joysticks position = sys.stick.direction(0); //0 = teclado, 1 = joy A, 2 = joy B if (sys.stick.triggerA(1)==true) { trigger = sys.stick.triggerB(1); } }
|
|
|
En línea
|
|
|
|
samsaga2
|
|
« Respuesta #6 : 12 de Noviembre de 2011, 08:34:07 am » |
|
La idea es incluir soporte asm incrustado y namespaces con lo que se podría hacer una librería externa con todo eso. Una idea: Al lenguaje le añadiría unos objetos (creo que similar a como funcionan los widgets de macOS), para acceder el hardware y facilitar la vida al programador. Te mando un ejemplo de como podría ser. Espero que te sirva. Muchos podrían ser sustituidos por llamadas a la BIOS, aunque eso implicaría a que el resultado fuera una ROM. void prueba() { // definicion de variables var data = new Array(100,110,110,100,44,44,32,32); byte position; byte value; byte A; // 8 bits int HL; // 16 bits boolean trigger=false; A++; // autoincremento A--; value = sys.msx.gen; //variable de sistema, proporciona el codigo de generacion de MSX //value = sys.ram.size; vdp.screen.setMode(2); // inicializa el modo de pantalla value = vdp.screen.mode; // lee el modo de pantalla vdp.sprite.setMode(1); // inicializa el modo de sprites: 0=8x8; 1=16x16 vdp.sprite.zoom = false; // activa el modo zoom de los sprites vdp.vram.writeBlock(0x3800,data); // escribe un bloque de datos en la VRAM vdp.vram.poke(0x1B01,20); // escribe un byte en la VRAM value = vdp.vram.peek(0x1B01); // lee un byte de la VRAM // funciones que actuan directamente con la tabla de nombre de patrones vdp.tile.set(x,y,value); value = vdp.tile.get(x,y); // funciones para imprimir texto en la pantalla // actuan directamente con la tabla de nombre de patrones // validas incluso para screen2 // Nota: la ultima posición se guarda en una variable de sistema vdp.locate(x,y); // base(0)+(y*32)+x con base 5 para sc1 o 10 para sc2 vdp.print(cadena); //accede a los registros del vdp vdp.set(0,12); value = vdp.get(0); // acceso a los atributos de los sprites // idea: funcion para definir sprite vdp.sprite.setPlane(0,1); // asigna un sprite a un plano de pantalla vdp.sprite.setPosition(1,100,120); // (num plano, x,y) vdp.sprite.setColor(1,15); // (num plano, color) vdp.sprite.visible(1) = false; // (num plano) posiciona el sprite y=209 // haciendolo oculto // acceso al PSG psg.channelA.volume = 15; psg.channelA.frequency = 1500; psg.channelA.tone = true; psg.channelA.noise = false; // idem para B y C psg.noise.period = 31; psg.envelope.period =1000; psg.envelope.wave = 1; // acceso a la RAM sys.ram.poke(1000,10); value = sys.ram.peek(1000); // acceso al teclado value = ppi.key(0); //num de fila // acceso a los joysticks position = sys.stick.direction(0); //0 = teclado, 1 = joy A, 2 = joy B if (sys.stick.triggerA(1)==true) { trigger = sys.stick.triggerB(1); } }
|
|
|
En línea
|
|
|
|
theNestruo
|
|
« Respuesta #7 : 13 de Noviembre de 2011, 10:27:25 am » |
|
Yo pensé hacer algo parecido en Java (...), pero más pensado para RAD y bocetos en PC que un compilador fina para Z80. Es decir programabas en Java con unas funciones para acceder a los recursos de un MSX que funcionaría en el emulador (Tomando atajos), (...)
Para RAD y bocetos yo me plantearía utilizar BASIC y emuladores (a los que puedes subir la velocidad de emulación). Las herramientas ya existen y el lenguaje es conocido. A menos que haya algo más que no esté viendo, ¿lo otro no sería matar moscas a cañonazos?
|
|
|
En línea
|
theNestruo."Old BASIC programmers never die; they GOSUB but never RETURN."
|
|
|
Mortimer
|
|
« Respuesta #8 : 13 de Noviembre de 2011, 07:50:22 pm » |
|
Para RAD y bocetos yo me plantearía utilizar BASIC y emuladores (a los que puedes subir la velocidad de emulación). Las herramientas ya existen y el lenguaje es conocido. A menos que haya algo más que no esté viendo, ¿lo otro no sería matar moscas a cañonazos?
Pero basic tiene tantas limitaciones de expresividad, que la idea era hacer algo que pudiera aprovechar la potencia de los ordenadores actuales y las facilidades de los lenguajes modernos. Algo con control muy directo a los recursos, como comenta aorante, como si tuvieras un PC con un TMS9918... Pero bueno, al final el proyecto tomó otros derroteros, y ya yo tampoco le veo demasiado sentido.
|
|
|
En línea
|
|
|
|
samsaga2
|
|
« Respuesta #9 : 15 de Noviembre de 2011, 09:46:19 am » |
|
De momento voy a concentrarme sólo en la versión pseudo c#. Bastante trabajo me dará como para hacer también un Basic (puede que en futuro). Pero la verdad es que me haría más ilusión meter un forth que un basic (sería y muchísimo más fácil).
|
|
|
En línea
|
|
|
|
Metalbrain
Karoshi Fan
Mensajes: 92
Z80jutsushi
|
|
« Respuesta #10 : 15 de Noviembre de 2011, 12:58:36 pm » |
|
La idea sería tener un cross-compiler para basic y un lenguaje moderno estilo c# ya que no hay nada parecido para msx y ni z80 en general. ¿Conoces el ccz80? Creo que es algo similar, aunque con sintaxis mas o menos basada en C: http://www.telefonica.net/web2/emilioguerrero/ccz80/ccz80sp.html
|
|
|
En línea
|
|
|
|
samsaga2
|
|
« Respuesta #11 : 16 de Noviembre de 2011, 12:16:20 pm » |
|
Lo había visto muy por encima pero el código fuente no es libre, sólo soporta spectrum y no soy demasiado fan de su sintaxis. Voy avanzando ahora tengo soporte de argumentos y estoy haciendo pruebas con condicionales: int test1(bool arg0, int arg1) { if(arg0) return arg1+arg1;
return arg1; }
int test2() { return test1(true, 1)+test1(false, 3); }
Se compila a: ; test1 ; arg arg0 in l ; arg arg1 in de _test1: ld a,l or a jr z $b1 ld hl,de add hl,de ret b1: ld hl,de ret
; test2 _test2: ld l,255 ld de,1 call _test1 ld bc,hl ld l,0 ld de,3 call _test1 add hl,bc ret
El mismo código en el sdcc se queda en: 1 ;-------------------------------------------------------- 2 ; File Created by SDCC : free open source ANSI-C Compiler 3 ; Version 3.0.6 #7037 (Nov 16 2011) (CYGWIN) 4 ; This file was generated Wed Nov 16 12:04:29 2011 5 ;-------------------------------------------------------- 6 .module kk 7 .optsdcc -mz80 8 9 ;-------------------------------------------------------- 10 ; Public variables in this module 11 ;-------------------------------------------------------- 12 .globl _test2 13 .globl _test1 14 ;-------------------------------------------------------- 15 ; special function registers 16 ;-------------------------------------------------------- 17 ;-------------------------------------------------------- 18 ; ram data 19 ;-------------------------------------------------------- 20 .area _DATA 21 ;-------------------------------------------------------- 22 ; overlayable items in ram 23 ;-------------------------------------------------------- 24 .area _OVERLAY 25 ;-------------------------------------------------------- 26 ; external initialized ram data 27 ;-------------------------------------------------------- 28 ;-------------------------------------------------------- 29 ; global & static initialisations 30 ;-------------------------------------------------------- 31 .area _HOME 32 .area _GSINIT 33 .area _GSFINAL 34 .area _GSINIT 35 ;-------------------------------------------------------- 36 ; Home 37 ;-------------------------------------------------------- 38 .area _HOME 39 .area _HOME 40 ;-------------------------------------------------------- 41 ; code 42 ;-------------------------------------------------------- 43 .area _CODE 44 ;kk.c:5: bool test1(bool arg0, int arg1) 45 ; --------------------------------- 46 ; Function test1 47 ; --------------------------------- 0000 48 _test1_start:: 0000 49 _test1: 0000 DD E5 50 push ix 0002 DD 21 00 00 51 ld ix,#0 0006 DD 39 52 add ix,sp 53 ;kk.c:7: if(arg0) 0008 DD 7E 04 54 ld a,4 (ix) 000B B7 55 or a, a 000C 28 07 56 jr Z,00102$ 57 ;kk.c:8: return arg1 + arg1; 000E DD 7E 05 58 ld a,5 (ix) 0011 87 59 add a, a 0012 6F 60 ld l,a 0013 18 02 61 jr 00103$ 0015 62 00102$: 63 ;kk.c:10: return true; 0015 2E FF 64 ld l,#0xFF 0017 65 00103$: 0017 DD E1 66 pop ix 0019 C9 67 ret 001A 68 _test1_end:: 69 ;kk.c:13: bool test2() 70 ; --------------------------------- 71 ; Function test2 72 ; --------------------------------- 001A 73 _test2_start:: 001A 74 _test2: 75 ;kk.c:15: return test1(true, 1) + test1(false, 3); 001A 21 01 00 76 ld hl,#0x0001 001D E5 77 push hl 001E 3E FF 78 ld a,#0xFF 0020 F5 79 push af 0021 33 80 inc sp 0022 CDr00s00 81 call _test1 0025 F1 82 pop af 0026 33 83 inc sp 0027 55 84 ld d,l 0028 D5 85 push de 0029 21 03 00 86 ld hl,#0x0003 002C E5 87 push hl 002D 3E 00 88 ld a,#0x00 002F F5 89 push af 0030 33 90 inc sp 0031 CDr00s00 91 call _test1 0034 F1 92 pop af 0035 33 93 inc sp 0036 D1 94 pop de 0037 7A 95 ld a,d 0038 85 96 add a, l 0039 6F 97 ld l,a 003A C9 98 ret 003B 99 _test2_end:: 100 .area _CODE 101 .area _CABS
Ops, bug gordo en la linia 59 (¿porqué suma bytes si arg1 es un int?). Como ves es una mejora importante respecto al sdcc. Pero aún está muy lejos el que sea un compilador usable.
|
|
|
En línea
|
|
|
|
|
samsaga2
|
|
« Respuesta #13 : 01 de Diciembre de 2011, 12:15:32 pm » |
|
El primer programa funcional con el compilador: namespace Z80 { void di() { asm("di"); }
void ei() { asm("ei"); } }
namespace MSX.Keyboard { void disableClick() { asm("xor a ld (0f3dbh),a"); }
void enableClick() { asm("ld a,1 ld (0f3dbh),a"); }
byte readChar() { return asm("call 009fh", "", "byte:a"); } }
namespace MSX.Screen { void setMode(byte mode) { asm("call 005fh", "mode:a"); }
void setColor(byte foreground, byte background, byte border) { asm("ld (0f3e9h),hl ld a,e ld (0f3ebh),a call 0062h", "foreground:l, background:h, border:e"); }
void fillVRAM(word addr, word len, byte data) { asm("call 0056h", "addr:hl, len:bc, data:a"); }
void writeRAM(word addr, byte value) { asm("call 0177h", "addr:hl, value:a"); }
void putChar(byte char) { asm("call 00a2h", "char:a"); } }
using MSX;
namespace Program { void init() { Keyboard.disableClick(); Screen.setMode(1b); Screen.setColor(15b, 0b, 0b); }
void start() { Z80.di(); init(); while(true) { Screen.putChar(Keyboard.readChar()); } } }
Se compila a... ; Z80.di _Z80_di: di ret
; Z80.ei _Z80_ei: ei ret
; MSX.Keyboard.disableClick _MSX_Keyboard_disableClick: xor a ld (0f3dbh),a ret
; MSX.Keyboard.enableClick _MSX_Keyboard_enableClick: ld a,1 ld (0f3dbh),a ret
; MSX.Keyboard.readChar _MSX_Keyboard_readChar: call 009fh ld l,a ret
; MSX.Screen.setMode ; arg mode in l _MSX_Screen_setMode: ld a,l call 005fh ret
; MSX.Screen.setColor ; arg foreground in l ; arg background in h ; arg border in e _MSX_Screen_setColor: ld (0f3e9h),hl ld a,e ld (0f3ebh),a call 0062h ret
; MSX.Screen.fillVRAM ; arg addr in hl ; arg len in de ; arg data in c _MSX_Screen_fillVRAM: ld c,e ld b,d ld a,c call 0056h ret
; MSX.Screen.writeRAM ; arg addr in hl ; arg value in e _MSX_Screen_writeRAM: ld a,e call 0177h ret
; MSX.Screen.putChar ; arg char in l _MSX_Screen_putChar: ld a,l call 00a2h ret
; Program.init _Program_init: call _MSX_Keyboard_disableClick ld l,1 call _MSX_Screen_setMode ld hl,15 + 0 * 256 ld e,0 call _MSX_Screen_setColor ret
; Program.start _Program_start: call _Z80_di call _Program_init b1: call _MSX_Keyboard_readChar call _MSX_Screen_putChar jr b1 b2: ret
Los tres primeros parámetros de las funciones se pasan en los registros hl, de y bc. Además el register allocator minimiza el uso de variables en la pila (que son los dos problemsa principales del sdcc y el hitech-c). Cuando implemente el inline de funciones el código quedará aún mucho más optimizado. Ya que eliminará calls, rets y loads innecesarios.
|
|
|
En línea
|
|
|
|
kabish
|
|
« Respuesta #14 : 01 de Diciembre de 2011, 11:04:52 pm » |
|
Muy interesante.
|
|
|
En línea
|
|
|
|
|