From: michaelh Date: Thu, 17 Feb 2000 05:24:36 +0000 (+0000) Subject: Added support for the gb, touched some files in testing the port. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=6a01e2d7d2353eb11e862f332bc2df43a967b9fa;p=fw%2Fsdcc Added support for the gb, touched some files in testing the port. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@110 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/as/z80/Makefile b/as/z80/Makefile index 5d362a7f..25fce800 100644 --- a/as/z80/Makefile +++ b/as/z80/Makefile @@ -7,7 +7,7 @@ OBJS = asdata.o asexpr.o aslex.o aslist.o asmain.o asout.o \ assubr.o assym.o z80adr.o z80ext.o z80mch.o z80pst.o BINS = as$E -CFLAGS += -funsigned-char +CFLAGS += -funsigned-char -ggdb LDFLAGS += -lm all: $(BINS) diff --git a/device/lib/gbz80/Makefile b/device/lib/gbz80/Makefile new file mode 100644 index 00000000..51989aa2 --- /dev/null +++ b/device/lib/gbz80/Makefile @@ -0,0 +1,25 @@ +# libc/z80 Makefile + +TOPDIR = ../../.. + +SCC = $(TOPDIR)/bin/sdcc -mgbz80 -v +SAS = as-gb + +OBJ = putchar.o string.o printf.o # asm_strings.o div.o mul.o +LIB = z80.lib +CC = $(SCC) +AS = $(SAS) +CFLAGS = -I../include -I. --dumpall + +all: $(LIB) crt0.o + +$(LIB): $(OBJ) Makefile _dummy + rm -f $(LIB) + for i in $(OBJ); do echo $$i >> $(LIB); done + +_dummy: + +clean: + rm -f $(OBJ) *~ $(CLEANSPEC) + + diff --git a/device/lib/gbz80/README b/device/lib/gbz80/README new file mode 100644 index 00000000..a34ea453 --- /dev/null +++ b/device/lib/gbz80/README @@ -0,0 +1,4 @@ +sdcc/device/lib/z80 +------------------- + +Z80 specific routines. diff --git a/device/lib/gbz80/asm_strings.s b/device/lib/gbz80/asm_strings.s new file mode 100644 index 00000000..fd263927 --- /dev/null +++ b/device/lib/gbz80/asm_strings.s @@ -0,0 +1,102 @@ + ;; Implementation of some string functions in + ;; assembler. + + ;; Why - because I want a better dhrystone score :) + +; char *strcpy(char *dest, const char *source) +_strcpy:: + push de + push ix + ld ix,#0 + add ix,sp + ld l,6(ix) + ld h,7(ix) + ld e,8(ix) + ld d,9(ix) + + push hl +1$: + ld a,(de) + ld (hl),a + inc hl + inc de + or a,a + jr nz,1$ + + pop hl + pop ix + pop de + ret + +; void *memcpy(void *dest, const void *source, int count) +_memcpy:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + ld l,8(ix) + ld h,9(ix) + ld e,10(ix) + ld d,11(ix) + ld c,12(ix) + ld b,13(ix) + + inc b + inc c + push hl + + jr 2$ +1$: + ld a,(de) + ld (hl),a + inc de + inc hl +2$: + dec c + jr nz,1$ + dec b + jr nz,1$ + + pop hl + pop ix + pop bc + pop de + ret + +; int strcmp(const char *s1, const char *s2) +_strcmp:: + push de + push ix + ld ix,#0 + add ix,sp + ld e,6(ix) + ld d,7(ix) + ld l,8(ix) + ld h,9(ix) + + jr 1$ +2$: + ld a,(de) + sub (hl) + jr nz,4$ + ;; A == 0 + cp (hl) + jr z,3$ +1$: + inc de + inc hl + jr 2$ + +3$: + ld hl,#0 + jr 5$ +4$: + ld hl,#1 + jr nc,5$ + ld hl,#-1 +5$: + pop ix + pop de + ret + \ No newline at end of file diff --git a/device/lib/gbz80/crt0.s b/device/lib/gbz80/crt0.s new file mode 100644 index 00000000..eb015280 --- /dev/null +++ b/device/lib/gbz80/crt0.s @@ -0,0 +1,62 @@ + ;; Generic crt0.s for a Z80 + .globl __main + + .area _HEADER (ABS) + ;; Reset vector + .org 0 + jp init + + .org 0x08 + reti + .org 0x10 + reti + .org 0x18 + reti + .org 0x20 + reti + .org 0x28 + reti + .org 0x30 + reti + .org 0x38 + reti + + .org 0x100 + jp 0x150 + + .org 0x150 +init: + di + ;; Stack at the top of memory. + ld sp,#0xdfff + + ;; Use _main instead of main to bypass sdcc's intelligence + call __main + jp _exit + + ;; Ordering of segments for the linker. + .area _CODE + .area _DATA + +__clock:: + ld a,#2 + rst 0x00 + ret + +_getsp:: + ld hl,#0 + add hl,sp + ret + +__printTStates:: + ld a,#3 + rst 0x00 + ret + +_exit:: + ;; Exit - special code to the emulator + ld a,#1 + rst 0x00 +1$: + halt + jr 1$ diff --git a/device/lib/gbz80/div.s b/device/lib/gbz80/div.s new file mode 100644 index 00000000..5917c24a --- /dev/null +++ b/device/lib/gbz80/div.s @@ -0,0 +1,318 @@ + ;; Originally from GBDK by Pascal Felber. + .area _CODE + +__divschar:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld e,9(ix) + call .div8 + + ld l,c + + pop ix + pop bc + pop de + ret + +__modschar:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld e,9(ix) + call .div8 + + ld l,e + + pop ix + pop bc + pop de + ret + +__divsint:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld b,9(ix) + ld e,10(ix) + ld d,11(ix) + call .div16 + + ld l,c + ld h,b + + pop ix + pop bc + pop de + ret + +__modsint:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld b,9(ix) + ld e,10(ix) + ld d,11(ix) + call .div16 + + ld l,e + ld h,d + + pop ix + pop bc + pop de + ret + + ;; Unsigned +__divuchar:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld e,9(ix) + call .divu8 + + ld l,c + + pop ix + pop bc + pop de + ret + +__moduchar:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld e,9(ix) + call .divu8 + + ld l,e + + pop ix + pop bc + pop de + ret + +__divuint:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld b,9(ix) + ld e,10(ix) + ld d,11(ix) + call .divu16 + + ld l,c + ld h,b + + pop ix + pop bc + pop de + ret + +__moduint:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld b,9(ix) + ld e,10(ix) + ld d,11(ix) + call .divu16 + + ld l,e + ld h,d + + pop ix + pop bc + pop de + ret + +.div8:: +.mod8:: + LD A,C ; Sign extend + RLCA + SBC A + LD B,A + LD A,E ; Sign extend + RLCA + SBC A + LD D,A + + ; Fall through to .div16 + + ;; 16-bit division + ;; + ;; Entry conditions + ;; BC = dividend + ;; DE = divisor + ;; + ;; Exit conditions + ;; BC = quotient + ;; DE = remainder + ;; If divisor is non-zero, carry=0 + ;; If divisor is 0, carry=1 and both quotient and remainder are 0 + ;; + ;; Register used: AF,BC,DE,HL +.div16:: +.mod16:: + ;; Determine sign of quotient by xor-ing high bytes of dividend + ;; and divisor. Quotient is positive if signs are the same, negative + ;; if signs are different + ;; Remainder has same sign as dividend + LD A,B ; Get high byte of dividend + LD (.srem),A ; Save as sign of remainder + XOR D ; Xor with high byte of divisor + LD (.squot),A ; Save sign of quotient + ;; Take absolute value of divisor + BIT 7,D + JR Z,.chkde ; Jump if divisor is positive + SUB A ; Substract divisor from 0 + SUB E + LD E,A + SBC A ; Propagate borrow (A=0xFF if borrow) + SUB D + LD D,A + ;; Take absolute value of dividend +.chkde: + BIT 7,B + JR Z,.dodiv ; Jump if dividend is positive + SUB A ; Substract dividend from 0 + SUB C + LD C,A + SBC A ; Propagate borrow (A=0xFF if borrow) + SUB B + LD B,A + ;; Divide absolute values +.dodiv: + CALL .divu16 + RET C ; Exit if divide by zero + ;; Negate quotient if it is negative + LD A,(.squot) + AND #0x80 + JR Z,.dorem ; Jump if quotient is positive + SUB A ; Substract quotient from 0 + SUB C + LD C,A + SBC A ; Propagate borrow (A=0xFF if borrow) + SUB B + LD B,A +.dorem: + ;; Negate remainder if it is negative + LD A,(.srem) + AND #0x80 + RET Z ; Return if remainder is positive + SUB A ; Substract remainder from 0 + SUB E + LD E,A + SBC A ; Propagate remainder (A=0xFF if borrow) + SUB D + LD D,A + RET + +.divu8:: +.modu8:: + LD B,#0x00 + LD D,B + ; Fall through to divu16 + +.divu16:: +.modu16:: + ;; Check for division by zero + LD A,E + OR D + JR NZ,.divide ; Branch if divisor is non-zero + LD BC,#0x00 ; Divide by zero error + LD D,B + LD E,C + SCF ; Set carry, invalid result + RET +.divide: + LD L,C ; L = low byte of dividend/quotient + LD H,B ; H = high byte of dividend/quotient + LD BC,#0x00 ; BC = remainder + OR A ; Clear carry to start + LD A,#16 ; 16 bits in dividend +.dvloop: + ;; Shift next bit of quotient into bit 0 of dividend + ;; Shift next MSB of dividend into LSB of remainder + ;; BC holds both dividend and quotient. While we shift a bit from + ;; MSB of dividend, we shift next bit of quotient in from carry + ;; HL holds remainder + ;; Do a 32-bit left shift, shifting carry to L, L to H, + ;; H to C, C to B + LD (.dcnt),A + RL L ; Carry (next bit of quotient) to bit 0 + RL H ; Shift remaining bytes + RL C + RL B ; Clears carry since BC was 0 + ;; If remainder is >= divisor, next bit of quotient is 1. This + ;; bit goes to carry + PUSH BC ; Save current remainder + LD A,C ; Substract divisor from remainder + SBC E + LD C,A + LD A,B + SBC D + LD B,A + CCF ; Complement borrow so 1 indicates a + ; successful substraction (this is the + ; next bit of quotient) + JR C,.drop ; Jump if remainder is >= dividend + POP BC ; Otherwise, restore remainder + JR .nodrop +.drop: + INC SP + INC SP +.nodrop: + LD A,(.dcnt) + DEC A ; DEC does not affect carry flag + JR NZ,.dvloop + ;; Shift last carry bit into quotient + LD D,B ; DE = remainder + LD E,C + RL L ; Carry to L + LD C,L ; C = low byte of quotient + RL H + LD B,H ; B = high byte of quotient + OR A ; Clear carry, valid result + RET + + .area _BSS + +.srem: + .ds 0x01 ; Sign of quotient +.squot: + .ds 0x01 ; Sign of remainder +.dcnt: + .ds 0x01 ; Counter for division diff --git a/device/lib/gbz80/mul.s b/device/lib/gbz80/mul.s new file mode 100644 index 00000000..57c06a91 --- /dev/null +++ b/device/lib/gbz80/mul.s @@ -0,0 +1,78 @@ + ;; Originally from GBDK by Pascal Felber. + + .area _CODE +__mulschar:: +__muluchar:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld e,9(ix) + call .mulu8 + + pop ix + pop bc + pop de + ret + +__mulsint:: +__muluint:: + push de + push bc + push ix + ld ix,#0 + add ix,sp + + ld c,8(ix) + ld b,9(ix) + ld e,10(ix) + ld d,11(ix) + call .mulu16 + + pop ix + pop bc + pop de + ret + +.mul8: +.mulu8: + LD B,#0x00 ; Sign extend is not necessary with mul + LD D,B + ; Fall through + + ;; 16-bit multiplication + ;; + ;; Entry conditions + ;; BC = multiplicand + ;; DE = multiplier + ;; + ;; Exit conditions + ;; DE = less significant word of product + ;; + ;; Register used: AF,BC,DE,HL +.mul16: +.mulu16: + LD HL,#0x00 ; Product = 0 + LD A,#15 ; Count = bit length - 1 + ;; Shift-and-add algorithm + ;; If MSB of multiplier is 1, add multiplicand to partial product + ;; Shift partial product, multiplier left 1 bit +.mlp: + SLA E ; Shift multiplier left 1 bit + RL D + JR NC,.mlp1 ; Jump if MSB of multiplier = 0 + ADD HL,BC ; Add multiplicand to partial product +.mlp1: + ADD HL,HL ; Shift partial product left + DEC A + JR NZ,.mlp ; Continue until count = 0 + ;; Add multiplicand one last time if MSB of multiplier is 1 + BIT 7,D ; Get MSB of multiplier + JR Z,.mend ; Exit if MSB of multiplier is 0 + ADD HL,BC ; Add multiplicand to product +.mend: + RET ; HL = result + diff --git a/device/lib/gbz80/printf.c b/device/lib/gbz80/printf.c new file mode 100644 index 00000000..40a57ecc --- /dev/null +++ b/device/lib/gbz80/printf.c @@ -0,0 +1,96 @@ +/** Simple printf implementation + Again a stub - will use the std one later... +*/ + +#include + +#define NULL 0 + +/* A hack because I dont understand how va_arg works... + sdcc pushes right to left with the real sizes, not cast up + to an int. + so printf(int, char, long) + results in push long, push char, push int + On the z80 the stack grows down, so the things seem to be in + the correct order. + */ + +typedef char * va_list; +#define va_start(list, last) list = (char *)&last + sizeof(last) +#define va_arg(list, type) *(type *)list; list += sizeof(type); + +typedef void EMIT(char c, void *pData); + + +static void _printn(unsigned u, unsigned base, char issigned, EMIT *emitter, void *pData) +{ + const char *_hex = "0123456789ABCDEF"; + if (issigned && ((int)u < 0)) { + (*emitter)('-', pData); + u = (unsigned)-((int)u); + } + if (u >= base) + _printn(u/base, base, 0, emitter, pData); + (*emitter)(_hex[u%base], pData); +} + +static void _printf(const char *format, EMIT *emitter, void *pData, va_list va) +{ + while (*format) { + putchar(*format); +#if 0 + if (*format == '%') { + switch (*++format) { + case 'c': { + char c = va_arg(va, char); + (*emitter)(c, pData); + break; + } + case 'u': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 0, emitter, pData); + break; + } + case 'd': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 1, emitter, pData); + break; + } + case 'x': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 16, 0, emitter, pData); + break; + } + case 's': + { + char *s = va_arg(va, char *); + while (*s) { + (*emitter)(*s, pData); + s++; + } + } + } + } + else { + (*emitter)(*format, pData); + } +#endif + format++; + } +} + +static void _char_emitter(char c, void *pData) +{ + putchar(c); +} + +void printf(const char *format, ...) +{ + va_list va; + va_start(va, format); + + _printf(format, _char_emitter, NULL, va); +} diff --git a/device/lib/gbz80/putchar.s b/device/lib/gbz80/putchar.s new file mode 100644 index 00000000..509d8aa6 --- /dev/null +++ b/device/lib/gbz80/putchar.s @@ -0,0 +1,22 @@ + .area _CODE +_putchar:: + lda hl,2(sp) + ld l,(hl) + ld a,#0 + rst 0x00 + ret + +.if 0 +_putchar:: + push ix + ld ix,#0 + add ix,sp + + ld l,4(ix) + ld a,#0 + out (0xff),a + + pop ix + ret +.endif + diff --git a/device/lib/gbz80/string.c b/device/lib/gbz80/string.c new file mode 100644 index 00000000..53ee9b2c --- /dev/null +++ b/device/lib/gbz80/string.c @@ -0,0 +1,34 @@ +/* Dumb strings stub. + Wanted a quick hack for now - will use the libc version later. +*/ +char *strcpy(char *dest, const char *source) +{ + char *d = dest; + const char *s = source; + while (*d++ = *s++); + return dest; +} + +void *memcpy(void *dest, const void *source, int count) +{ + char *d = dest; + const char *s = source; + while (count--) + *d++ = *s++; + + return dest; +} + +int strcmp(const char *s1, const char *s2) +{ + char ret = 0; + + while (!(ret = *s1 - *s2) && *s2) + ++s1, ++s2; + + if (ret < 0) + return -1; + else if (ret > 0) + return 1; + return 0; +} diff --git a/device/lib/z80/Makefile b/device/lib/z80/Makefile index e70eee38..4dbb50f8 100644 --- a/device/lib/z80/Makefile +++ b/device/lib/z80/Makefile @@ -21,5 +21,3 @@ _dummy: clean: rm -f $(OBJ) *~ $(CLEANSPEC) - - diff --git a/device/lib/z80/printf.c b/device/lib/z80/printf.c index 6974ca7b..1ee76cbc 100644 --- a/device/lib/z80/printf.c +++ b/device/lib/z80/printf.c @@ -90,4 +90,5 @@ void printf(const char *format, ...) va_start(va, format); _printf(format, _char_emitter, NULL, va); + _printf(format, _char_emitter, NULL, va); } diff --git a/doc/random-notes.txt b/doc/random-notes.txt new file mode 100644 index 00000000..4c77790e --- /dev/null +++ b/doc/random-notes.txt @@ -0,0 +1,55 @@ +Random notes +------------ + +A random set of notes about sdcc and how it works. + +Michael: +-------- +Tracing parmBytes and function calls. + +Bug: +void printf(const char *format); + +void puts(const char *s) +{ + printf(s); +} + +Generates the pseudo-code: + hl = s + push hl + call printf + pop l (not hl - so parmBytes is too small) + +parmBytes for a function call seems to be setup in geniCodeCall in +SDCCicode.c. + +geniCodeCall: +* Takes care of calls with side effects (?) +* Generates the icode to push the parameters (this also computes the + resulting stack size) +* Generates a CALL or PCALL depending on if its a function or pointer to. +* Computes the result +* Adds the code for the call to the chain. + +My bug is probably in geniCodeParms - it's probably computing the +size of pointers wrong. + +geniCodeParms: +* A 'parm' node causes this to be run on the tree branches. +* It switches on the stack mode and sendto mode, and adds the + instructions required to push or put. +* A push adds the result of 'getSize' to the stack size. + +So the bug is probably in getSize. 's' is not an aggregate, so the +bug is in getSize(). + +It seems that IS_SPEC() is being set, deferencing *s so that it's size +is sizeof(char) == 1. It's either a SPECIFIER or a DECLARATOR - seems that +were the wrong way around. This is set in SDCCsymt.c, SDCCval.c, and the +yacc file. SDCCsymt.c and SDCCval.c havnt really changed in 5 days - must +be SDCC.y. Nope, no changes. diff against 5 days ago shows only intersting +changes are in SDCCicode. Same with -14 days. + + + diff --git a/src/SDCCsymt.c b/src/SDCCsymt.c index 25040c1b..2a956ab5 100644 --- a/src/SDCCsymt.c +++ b/src/SDCCsymt.c @@ -532,20 +532,18 @@ unsigned int getSize ( link *p ) /* if nothing return 0 */ if ( ! p ) return 0 ; - if ( IS_SPEC(p) ) { /* if this is the specifier then */ - switch (SPEC_NOUN(p)) { /* depending on the specifier type */ case V_INT: return (IS_LONG(p) ? LONGSIZE : ( IS_SHORT(p) ? SHORTSIZE: INTSIZE)) ; case V_FLOAT: return FLOATSIZE ; case V_CHAR: - return CHARSIZE ; + return CHARSIZE ; case V_VOID: return 0 ; case V_STRUCT: - return SPEC_STRUCT(p)->size ; + return SPEC_STRUCT(p)->size ; case V_LABEL: return 0 ; case V_SBIT: diff --git a/support/tests/dhrystone/Makefile b/support/tests/dhrystone/Makefile index e87bc050..f5090adf 100644 --- a/support/tests/dhrystone/Makefile +++ b/support/tests/dhrystone/Makefile @@ -2,7 +2,7 @@ CC = /home/michaelh/projects/sdcc/bin/sdcc # -DNOENUM is here to make the results more predictable -CFLAGS = -mz80 -v --dumpall +CFLAGS = -mgbz80 -v --dumpall CFLAGS += -DREG= -DNOSTRUCTASSIGN -DNOENUM -DBROKEN_SDCC=0 -DHZ=100 LIBDIR = /home/michaelh/projects/sdcc/device/lib/z80/ LD = link-z80 diff --git a/support/tests/dhrystone/dhry.c b/support/tests/dhrystone/dhry.c index f5acdc08..4c02ebea 100644 --- a/support/tests/dhrystone/dhry.c +++ b/support/tests/dhrystone/dhry.c @@ -73,7 +73,6 @@ char Ch_1_Glob, int Arr_1_Glob [50]; int Arr_2_Glob [50] [50]; - /* Used instead of malloc() */ static Rec_Type _r[2];