Hi Josb,
obviously also mine is just an opinion, and your is very appreciated by me
Also MSX-C code generator produces 8080-only opcodes: does not use IX, IY... but this is not always a penalty.
IIRC I was very impressed when I read about a C test program about solving the "Hanoi tower" problem and MSX-C could achieve the best results... this evening I must search for its sources, maybe we can make a comparison between MSX-C and BSD-C... and other compilers if anybody is willing to make some tests.
@ fukenko:
Did you read my previous post about contacting LSI?
What do you think about it?
I'm for the proposal,but actually it's a bit difficult to free MSX-C unless many users request to.
BTW,We had to buy runtime license from LSI when we distribute software made with MSX-C,but later when MSX MAGZAINE Eikyu-Hozon ban 3 was published,LSI allowed to distribute it without license,so we can distribute homebrew MSX-C software now.
Hi Josb,
sorry for late answer but I'm really busy.
Here is where I found the Hanoi tower sample: it comes from an Italian computer magazine very famous here in Italy.
In the old "golden days" MSX was mentioned and tech articles were extremely useful to me (even if some errata were found).
You should select the article from MC n.85 (May 1989) and go to page 221.
Although if in Italian you should be able to "get the sense" of the articles.
Here is a my version of hanoi sample:
#include <stdio.h> typedef VOID void; #define JIFFY (*((int *) 0xFC9E)) int nMoves; char *buffer; char *p; void storeMove(s,d) char s,d; { *p++ = s; *p++ = d; /* printf("%2d -> %2d\n", (int) s, (int) d); */ } void dumpMoves(q, i) char *q; int i; { while (i--) { printf("%2d", (int) *q); printf(" -> "); q++; printf("%2d", (int) *q); printf("\n"); q++; } } void storre(n, src, des, aus) char n, src, des, aus; { if (n > 0) { nMoves++; storre(n-1, src, aus, des); storeMove(src, des); storre(n-1, aus, des, src); } } void main() { int nDisk; int t0, t1; /* input number of disks */ printf("How many disks? "); if (1 != scanf("%d", &nDisk)) { printf("input error\n"); goto exit; } printf("nDisk = %d\n", nDisk); /* allocate buffer to store moves */ buffer = (char *) malloc(0x4000); if (NULL == buffer) { printf("out of memory\n"); goto exit; } /* reset vars */ nMoves = 0; p = buffer; /* log start time */ t0 = JIFFY; /* do work */ storre((char) nDisk, (char) 1, (char) 3, (char) 2); /* log stop time */ t1 = JIFFY; /* dump results with no hurry */ printf("elapsed tick(s) = %d\n", (t1 - t0)); printf("nMoves = %d\n", nMoves); dumpMoves(buffer, nMoves); exit: if (buffer) free(buffer); }
I use JIFFY to count how many vdp interrupts the function storre takes to do the cpu-intensive algorithm.
storre() makes all the calculations and store moves (as couple of bytes) in a mallocated array.
Moves are dumped later (function dumpMoves) to prevent i/o from altering storre() performance.
I compile this code with MSX-C without optimization.
I run the executable in blueMSX in z80 mode, vdp @ 60Hz.
In my tests I choose nDisk = 12.
I get a (stunning in my opinion) result of 59 ticks so less than a second to evaluate 4095 moves B-)
If you wish you can try the same with BDS...
I'm for the proposal,but actually it's a bit difficult to free MSX-C unless many users request to.
BTW,We had to buy runtime license from LSI when we distribute software made with MSX-C,but later when MSX MAGZAINE Eikyu-Hozon ban 3 was published,LSI allowed to distribute it without license,so we can distribute homebrew MSX-C software now.
Hi fukenko,
I should have a contact from LSI here in Italy.
Maybe you may try to contact LSI Japan...
Could MRC support our request?
Hi Josb,
sorry for late answer but I'm really busy.
don't worry, MSX can wait
If you wish you can try the same with BDS...
if you aren't in a hurry, I will try next weekend (I don't have any real MSX now)
I have just compield on HI-TECH v7.8 the hanoi test:
on opnemsx (msx2boosted) the hanoi tower runs in 84 ticks (12 disks)
Generally, recursive code (like this one) is not the best to do comparisons with HTC, as this latter uses IX,IY registers to point to heap and stack
Moreover, in HTC the "ancient" C convention in parameter passing disables the use of z80 registers in the functions
8080 compilers are usually faster when all the alghorithm is in the recursion itself, anyway, here follows the ASM code
global small_model ;stdlib.h: 122: extern int atexit(void (*)(void)); ;stdlib.h: 126: extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); ;stdlib.h: 127: extern void * bsearch(const void *, void *, size_t, size_t, int(*)(const void *, const void *)); ;HANOI.C: 21: { global _storeMove signat _storeMove,24 psect text,class=CODE global _p file "HANOI.C" line 21 _storeMove: push ix ld ix,0 add ix,sp ;HANOI.C: 22: *p++ = s; line 22 ld a,(ix+4) ld hl,(_p) inc hl ld (_p),hl dec hl ld (hl),a ;HANOI.C: 23: *p++ = d; line 23 ld a,(ix+6) inc hl inc hl ld (_p),hl dec hl ld (hl),a ;HANOI.C: 27: } line 27 pop ix ret global _dumpMoves signat _dumpMoves,24 global _printf signat _printf,26 ;HANOI.C: 31: int i; ;HANOI.C: 32: { line 32 _dumpMoves: push ix ld ix,0 add ix,sp push iy ; _q loaded to iy line 33 ld l,(ix+4) ld h,(ix+5) push hl pop iy ;HANOI.C: 33: while (i--) jp l11 l12: ;HANOI.C: 34: { line 35 ld a,(iy+0) ld l,a rla sbc a,a ld h,a push hl ld hl,u19 push hl call _printf pop bc pop bc ;HANOI.C: 36: printf(" -> "); line 36 ld hl,u29 push hl call _printf pop bc ;HANOI.C: 37: q++; line 37 inc iy ;HANOI.C: 38: printf("%2d", (int) *q); line 38 ld a,(iy+0) ld l,a rla sbc a,a ld h,a push hl ld hl,u39 push hl call _printf pop bc pop bc ;HANOI.C: 39: printf("\n"); line 39 ld hl,u49 push hl call _printf pop bc ;HANOI.C: 40: q++; line 40 inc iy line 41 l11: ;HANOI.C: 41: } line 33 ld l,(ix+6) ld h,(ix+7) dec hl ld (ix+6),l ld (ix+7),h inc hl ld a,l or h jp nz,l12 ;HANOI.C: 42: } line 42 pop iy pop ix ret global _storre signat _storre,24 global _nMoves ;HANOI.C: 44: void storre(n, src, des, aus) ;HANOI.C: 45: char n, src, des, aus; ;HANOI.C: 46: { line 46 _storre: push ix ld ix,0 add ix,sp ;HANOI.C: 47: if (n > 0) line 47 ld a,(ix+4) xor 080h cp 081h jp c,l14 ;HANOI.C: 48: { line 49 ld hl,(_nMoves) inc hl ld (_nMoves),hl ;HANOI.C: 50: storre(n-1, src, aus, des); line 50 ld a,(ix+8) ld l,a rla sbc a,a ld h,a push hl ld a,(ix+10) ld l,a rla sbc a,a ld h,a push hl ld a,(ix+6) ld l,a rla sbc a,a ld h,a push hl ld hl,-1 ld a,(ix+4) add a,l ld l,a ld a,0 bit 07h,(ix+4) jp z,u15 dec a u15: adc a,h ld h,a push hl call _storre pop hl pop hl pop hl pop hl ;HANOI.C: 51: storeMove(src, des); ; _des loaded to d line 51 ld d,(ix+8) ; _src loaded to e ld e,(ix+6) ld a,d ld l,a rla sbc a,a ld h,a push hl ld a,e ld l,a rla sbc a,a ld h,a push hl call _storeMove pop hl pop hl ;HANOI.C: 52: storre(n-1, aus, des, src); line 52 ld a,e ld l,a rla sbc a,a ld h,a push hl ld a,d ld l,a rla sbc a,a ld h,a push hl ld a,(ix+10) ld l,a rla sbc a,a ld h,a push hl ld hl,-1 ld a,(ix+4) add a,l ld l,a ld a,0 bit 07h,(ix+4) jp z,u25 dec a u25: adc a,h ld h,a push hl call _storre pop hl pop hl pop hl pop hl ;HANOI.C: 53: } line 54 l14: pop ix ret global _main signat _main,24 global _fflush signat _fflush,4154 global __iob global _scanf signat _scanf,26 global _buffer global _malloc signat _malloc,4154 global _free signat _free,4152 ;HANOI.C: 56: void main() ;HANOI.C: 57: { line 57 _main: push ix ld ix,0 add ix,sp push bc push iy ;HANOI.C: 58: int nDisk; line 64 ld hl,u59 push hl call _printf pop bc ;HANOI.C: 65: fflush((&_iob[1])); line 65 ld de,__iob+0Ch call _fflush ;HANOI.C: 66: if (1 != scanf("%d", &nDisk)) line 66 push ix pop hl dec hl dec hl push hl ld hl,u69 push hl call _scanf pop bc pop bc ld a,l xor 01h or h jp z,l17 ;HANOI.C: 67: { line 68 ld hl,u79 L1: push hl call _printf ;HANOI.C: 69: goto exit; line 69 jp L2 line 70 l17: ;HANOI.C: 70: } line 71 ld l,(ix+-2) ld h,(ix+-1) push hl ld hl,u89 push hl call _printf pop bc pop bc ;HANOI.C: 75: buffer = (char *) malloc(0x4000); line 75 ld de,04000h call _malloc ld (_buffer),hl ;HANOI.C: 76: if (((void *)0) == buffer) line 76 ld a,h or l jp nz,l19 ;HANOI.C: 77: { line 78 ld hl,u99 jp L1 line 80 l19: ;HANOI.C: 80: } line 84 ld hl,0 ld (_nMoves),hl ;HANOI.C: 85: p = buffer; line 85 ld hl,(_buffer) ld (_p),hl ;HANOI.C: 89: t0 = (*((int *) 0xFC9E)); ; _t0 allocated to iy line 89 ld iy,(-866) ;HANOI.C: 93: storre((char) nDisk, (char) 1, (char) 3, (char) 2); line 93 ld hl,02h push hl ld hl,03h push hl ld hl,01h push hl ld a,(ix+-2) ld l,a rla sbc a,a ld h,a push hl call _storre pop hl pop hl pop hl pop hl ;HANOI.C: 97: t1 = (*((int *) 0xFC9E)); ; _t1 allocated to bc line 97 ld bc,(-866) ;HANOI.C: 101: printf("elapsed tick(s) = %d\n", (t1 - t0)); line 101 push iy pop de ld l,c ld h,b or a sbc hl,de push hl ld hl,u109 push hl call _printf pop bc pop bc ;HANOI.C: 102: printf("nMoves = %d\n", nMoves); line 102 ld hl,(_nMoves) push hl ld hl,u119 push hl call _printf pop bc L2: pop bc ;HANOI.C: 106: exit: ;HANOI.C: 107: if (buffer) line 107 ld hl,(_buffer) ld a,h or l jp z,l16 ;HANOI.C: 108: free(buffer); line 108 ld e,l ld d,h call _free ;HANOI.C: 109: } line 109 l16: pop iy ld sp,ix pop ix ret psect strings,class=CODE u19: u39: defb "%2d",0 u69: defb 37,100,0 u59: defb "How many disks? ",0 u29: defb " -> ",0 u99: defb "out of memory",10,0 u79: defb "input error",10,0 u119: defb "nMoves = %d",10,0 u89: defb 10,"nDisk = %d",10,0 u109: defb "elapsed tick(s) = %d" u49: defb 10,0 psect bss,class=DATA _buffer: defs 2 _nMoves: defs 2 _p: defs 2 psect text end
hi again, I've tried to compile the code (using openmsx-catapult) and I have to do some changes,
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "bdscio.h" #define JIFFY 0xFC9E int nMoves; char *buffer; char *p; void storeMove(s,d) char s,d; { *p++ = s; *p++ = d; /* printf("%2d -> %2d\n", (int) s, (int) d); */ } void dumpMoves(q, i) char *q; int i; { while (i--) { printf("%2d", *q); printf(" -> "); q++; printf("%2d", *q); printf("\n"); q++; } } void storre(n, src, des, aus) char n, src, des, aus; { if (n > 0) { nMoves++; storre(n-1, src, aus, des); storeMove(src, des); storre(n-1, aus, des, src); } } main(argc,argv) int argc; char *argv[]; { int nDisk; int t0, t1; /* input number of disks */ printf("How many disks? "); if (1 != scanf("%d", &nDisk)) { printf("input error\n"); goto exit; } printf("nDisk = %d\n", nDisk); /* allocate buffer to store moves */ buffer = malloc(0x4000); if (NULL == buffer) { printf("out of memory\n"); goto exit; } /* reset vars */ nMoves = 0; p = buffer; /* log start time */ t0 = peek(JIFFY); /* do work */ storre( nDisk, 1, 3, 2); /* log stop time */ t1 = peek(JIFFY); /* dump results with no hurry */ printf("elapsed tick(s) = %d\n", (t1 - t0)); printf("nMoves = %d\n", nMoves); dumpMoves(buffer, nMoves); exit: if (buffer) free(buffer); }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unfortunely, code is compiled by BDS-C but malloc function doesn't work when is linked,
haven't you got another code more simple?
Yes! I confirm: by moving to the modern C convention, the time to do the same work is only 65 ticks
Here the current C and ASM that gives 65 ticks on msx1 @ 60Hz
(it gives 53 ticks on msx1 at 50Hz)
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <unixio.h> #include <math.h> #include <sys.h> #include <string.h> #include <hitech.h> //typedef VOID void; #define JIFFY (*((int *) 0xFC9E)) int nMoves; char *buffer; char *p; void storeMove(char s,char d) //char s,d; { *p++ = s; *p++ = d; /* printf("%2d -> %2d\n", (int) s, (int) d); */ } void dumpMoves(char *q,int i) //char *q; //int i; { while (i--) { printf("%2d", (int) *q); printf(" -> "); q++; printf("%2d", (int) *q); printf("\n"); q++; } } void storre(char n,char src,char des,char aus) //char n, src, des, aus; { if (n > 0) { nMoves++; storre(n-1, src, aus, des); storeMove(src, des); storre(n-1, aus, des, src); } } void main() { int nDisk; int t0, t1; /* input number of disks */ printf("How many disks? "); fflush(stdout); if (1 != scanf("%d", &nDisk)) { printf("input error\n"); goto exit; } printf("\nnDisk = %d\n", nDisk); /* allocate buffer to store moves */ buffer = (char *) malloc(0x4000); if (NULL == buffer) { printf("out of memory\n"); goto exit; } /* reset vars */ nMoves = 0; p = buffer; /* log start time */ t0 = JIFFY; /* do work */ storre((char) nDisk, (char) 1, (char) 3, (char) 2); /* log stop time */ t1 = JIFFY; /* dump results with no hurry */ printf("elapsed tick(s) = %d\n", (t1 - t0)); printf("nMoves = %d\n", nMoves); //dumpMoves(buffer, nMoves); exit: if (buffer) free(buffer); }
global small_model ;stdlib.h: 122: extern int atexit(void (*)(void)); ;stdlib.h: 126: extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); ;stdlib.h: 127: extern void * bsearch(const void *, void *, size_t, size_t, int(*)(const void *, const void *)); global _storeMove signat _storeMove,8248 psect text,class=CODE global _p file "HANOI.C" line 21 _storeMove: ;HANOI.C: 22: *p++ = s; line 22 ld hl,(_p) inc hl ld (_p),hl dec hl ld (hl),e inc hl ;HANOI.C: 23: *p++ = d; line 23 inc hl ld (_p),hl dec hl ld (hl),c ;HANOI.C: 27: } line 27 ret global _dumpMoves signat _dumpMoves,8248 global _printf signat _printf,26 line 32 _dumpMoves: push ix ld ix,0 add ix,sp push bc push iy ; _q loaded to iy line 33 push de pop iy ;HANOI.C: 33: while (i--) jp l11 l12: ;HANOI.C: 34: { line 35 ld a,(iy+0) ld l,a rla sbc a,a ld h,a push hl ld hl,u19 push hl call _printf pop bc pop bc ;HANOI.C: 36: printf(" -> "); line 36 ld hl,u29 push hl call _printf pop bc ;HANOI.C: 37: q++; line 37 inc iy ;HANOI.C: 38: printf("%2d", (int) *q); line 38 ld a,(iy+0) ld l,a rla sbc a,a ld h,a push hl ld hl,u39 push hl call _printf pop bc pop bc ;HANOI.C: 39: printf("\n"); line 39 ld hl,u49 push hl call _printf pop bc ; _i loaded to bc ld c,(ix+-2) ld b,(ix+-1) ;HANOI.C: 40: q++; line 40 inc iy line 41 l11: ;HANOI.C: 41: } ;_i stored from bc line 33 ld (ix+-2),c ld (ix+-1),b ld l,c ld h,b dec hl ld (ix+-2),l ld (ix+-1),h inc hl ld a,l or h jp nz,l12 ;HANOI.C: 42: } line 42 pop iy ld sp,ix pop ix ret global _storre signat _storre,16440 global _nMoves ;HANOI.C: 44: void storre(char n,char src,char des,char aus) ;HANOI.C: 46: { line 46 _storre: push ix ld ix,0 add ix,sp push bc ;_src stored from c ld (ix+-2),c ;HANOI.C: 47: if (n > 0) ;_n stored from e line 47 ld (ix+-1),e ld a,e xor 080h cp 081h jp c,l14 ;HANOI.C: 48: { line 49 ld hl,(_nMoves) inc hl ld (_nMoves),hl ;HANOI.C: 50: storre(n-1, src, aus, des); line 50 ld l,(ix+4) push hl ld l,(ix+6) push hl ld a,e dec a ld e,a call _storre ;HANOI.C: 51: storeMove(src, des); line 51 ld c,(ix+4) ld e,(ix+-2) call _storeMove ;HANOI.C: 52: storre(n-1, aus, des, src); line 52 ld l,(ix+-2) push hl ld l,(ix+4) push hl ld c,(ix+6) ld a,(ix+-1) dec a ld e,a call _storre ;HANOI.C: 53: } line 54 l14: ld sp,ix pop ix pop hl pop af pop af jp (hl) global _main signat _main,24 global _fflush signat _fflush,4154 global __iob global _scanf signat _scanf,26 global _buffer global _malloc signat _malloc,4154 global _free signat _free,4152 ;HANOI.C: 56: void main() ;HANOI.C: 57: { line 57 _main: push ix ld ix,0 add ix,sp push bc push iy ;HANOI.C: 58: int nDisk; line 64 ld hl,u59 push hl call _printf pop bc ;HANOI.C: 65: fflush((&_iob[1])); line 65 ld de,__iob+0Ch call _fflush ;HANOI.C: 66: if (1 != scanf("%d", &nDisk)) line 66 push ix pop hl dec hl dec hl push hl ld hl,u69 push hl call _scanf pop bc pop bc ld a,l xor 01h or h jp z,l17 ;HANOI.C: 67: { line 68 ld hl,u79 L1: push hl call _printf ;HANOI.C: 69: goto exit; line 69 jp L2 line 70 l17: ;HANOI.C: 70: } line 71 ld l,(ix+-2) ld h,(ix+-1) push hl ld hl,u89 push hl call _printf pop bc pop bc ;HANOI.C: 75: buffer = (char *) malloc(0x4000); line 75 ld de,04000h call _malloc ld (_buffer),hl ;HANOI.C: 76: if (((void *)0) == buffer) line 76 ld a,h or l jp nz,l19 ;HANOI.C: 77: { line 78 ld hl,u99 jp L1 line 80 l19: ;HANOI.C: 80: } line 84 ld hl,0 ld (_nMoves),hl ;HANOI.C: 85: p = buffer; line 85 ld hl,(_buffer) ld (_p),hl ;HANOI.C: 89: t0 = (*((int *) 0xFC9E)); ; _t0 allocated to iy line 89 ld iy,(-866) ;HANOI.C: 93: storre((char) nDisk, (char) 1, (char) 3, (char) 2); line 93 ld l,02h push hl ld l,03h push hl ld c,01h ld e,(ix+-2) call _storre ;HANOI.C: 97: t1 = (*((int *) 0xFC9E)); ; _t1 allocated to bc line 97 ld bc,(-866) ;HANOI.C: 101: printf("elapsed tick(s) = %d\n", (t1 - t0)); line 101 push iy pop de ld l,c ld h,b or a sbc hl,de push hl ld hl,u109 push hl call _printf pop bc pop bc ;HANOI.C: 102: printf("nMoves = %d\n", nMoves); line 102 ld hl,(_nMoves) push hl ld hl,u119 push hl call _printf pop bc L2: pop bc ;HANOI.C: 106: exit: ;HANOI.C: 107: if (buffer) line 107 ld hl,(_buffer) ld a,h or l jp z,l16 ;HANOI.C: 108: free(buffer); line 108 ld e,l ld d,h call _free ;HANOI.C: 109: } line 109 l16: pop iy ld sp,ix pop ix ret psect strings,class=CODE u19: u39: defb "%2d",0 u69: defb 37,100,0 u59: defb "How many disks? ",0 u29: defb " -> ",0 u99: defb "out of memory",10,0 u79: defb "input error",10,0 u119: defb "nMoves = %d",10,0 u89: defb 10,"nDisk = %d",10,0 u109: defb "elapsed tick(s) = %d" u49: defb 10,0 psect bss,class=DATA _buffer: defs 2 _nMoves: defs 2 _p: defs 2 psect text end
I'm sorry, it's late for me
I only had to change "alloc" instead of "malloc" and it works perfectly (I am not quite useful at coding)
with the same code (and the same openmsx) it gives 108 ticks (at 50 Mhz, MSX2 NMS 8245) ... slow?
...perhaps tomorrow I will be awoke
Yes! I confirm: by moving to the modern C convention, the time to do the same work is only 65 ticks
Here the current C and ASM that gives 65 ticks on msx1 @ 60Hz
Good achievement
Usage of IX makes me think that HTC is compiling with debug support: sounds to me like IX points to stack base of current function and is a pointer to a pointers list containing stack bases of underlying functions.
I presume you should find a NULL (or a compiler custom wrapper value) when you reach the first function of your executable (spero di essermi capito )
Maybe you can get even better performance by istructing compiler to don't generate debug info and optimize for speed (if possible).
(it gives 53 ticks on msx1 at 50Hz)
(1 / 60) * 65 ticks = 1.08333 secs
(1 / 50) * 53 ticks = 1.06 secs
Considering that:
- start of test is not JIFFY-syncronized and
- 60Hz tests are slightly penalized by +20% of vdp interrupts
I would say that results coincide.