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)
--- /dev/null
+# 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)
+
+
--- /dev/null
+sdcc/device/lib/z80
+-------------------
+
+Z80 specific routines.
--- /dev/null
+ ;; 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
--- /dev/null
+ ;; 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$
--- /dev/null
+ ;; 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
--- /dev/null
+ ;; 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
+
--- /dev/null
+/** Simple printf implementation
+ Again a stub - will use the std one later...
+*/
+
+#include <stdio.h>
+
+#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);
+}
--- /dev/null
+ .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
+
--- /dev/null
+/* 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;
+}
clean:
rm -f $(OBJ) *~ $(CLEANSPEC)
-
-
va_start(va, format);
_printf(format, _char_emitter, NULL, va);
+ _printf(format, _char_emitter, NULL, va);
}
--- /dev/null
+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.
+
+
+
/* 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:
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
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
-
/* Used instead of malloc() */
static Rec_Type _r[2];