]> cloudbase.mooo.com Git - avrcpm.git/commitdiff
* I2C Support added
authorLeo <erbl259-lmu@yahoo.de>
Mon, 11 Feb 2013 21:34:04 +0000 (21:34 +0000)
committerLeo <erbl259-lmu@yahoo.de>
Mon, 11 Feb 2013 21:34:04 +0000 (21:34 +0000)
  - Generic I2C driver
  - PCF8574 8-bit I/O support
  - PCF8583 RTC support
* cpm/utils/AVRCLOCK.MAC
   - ZSDOS clock driver added
* cpm/utils/TIMER.MAC
   - renamed to ACT.MAC
* cpm/utils/RTCDEMO.PAS
   - Turbo Pascal program to demonstrate the I2C interface added.

git-svn-id: svn://cu.loc/avr-cpm/avrcpm/trunk@195 57430480-672e-4586-8877-bcf8adbbf3b7

13 files changed:
avr/Makefile
avr/avrcpm.asm
avr/config.inc
avr/i2c.asm [new file with mode: 0644]
avr/init.asm
avr/timer.asm
avr/virt_ports.asm
cpm/BIOS.MAC
cpm/CFGACPM.LIB
cpm/Makefile
cpm/utils/ACT.MAC [moved from cpm/utils/TIMER.MAC with 100% similarity]
cpm/utils/AVRCLOCK.MAC [new file with mode: 0644]
cpm/utils/RTCDEMO.PAS [new file with mode: 0644]

index 664425ff5a5c59c98b0dbb07251fa29a1ad79a8d..efc5b1c04e6c93cc39db1f175d9e049687e7c287 100644 (file)
@@ -10,6 +10,7 @@ BAUD = 57600
 #BAUD = 115200
 
 DRAM_8BIT = 1
+#I2C = 1
 
 TARGET = avrcpm
 ASRC0  = avrcpm.asm 
@@ -20,7 +21,7 @@ ASRC0 += dsk_cpm.asm dsk_fat16.asm dsk_fsys.asm dsk_mgr.asm dsk_ram.asm
 ASRC0 += 8080int-orig.asm 8080int.asm 8080int-jmp.asm 8080int-t3.asm 8080int-t3-jmp.asm Z80int-jmp.asm
 
 ifneq ($(DRAM_8BIT),0)
-  ASRC0 += dram-8bit.inc dram-8bit.asm sw-uart.asm 
+  ASRC0 += dram-8bit.inc dram-8bit.asm sw-uart.asm i2c.asm
 else
   ASRC0 += dram-4bit.inc dram-4bit.asm hw-uart.asm 
 endif
@@ -29,7 +30,10 @@ endif
 ASRC := $(ASRC0) svnrev.inc
 
 # Place -D or -U options here
-CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU) -DDRAM_8BIT=$(DRAM_8BIT)
+CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU) -DDRAM_8BIT=$(DRAM_8BIT) 
+ifdef I2C
+  CDEFS += -DI2C=$(I2C)
+endif
 
 ASPATH = C:/Programme/Atmel/AVR\ Tools/AvrAssembler2
 DEFS = $(ASPATH)/Appnotes
index 5103f779ee11f5aaf75f625b94e7312b254d662e..ff278dd1d00498cc404554f392d37787cd0dbc10 100644 (file)
        .org INT_VECTORS_SIZE
 
        .include "init.asm"
-#if DRAM_8BIT  /* Implies software uart */
+#if DRAM_8BIT                  /* Implies software uart */
        .include "sw-uart.asm"
        .include "dram-8bit.asm"
-#else  /* 4 bit RAM, hardware uart */
+       .include "i2c.asm"
+#else                          /* 4 bit RAM, hardware uart */
        .include "hw-uart.asm"
        .include "dram-4bit.asm"
 #endif
index f6d16c98f798e681990592049ac5a9f810539f1a..3d63410cde7512a24184f1cdae17b7e5aee44047 100644 (file)
 #ifndef BAUD
   #define BAUD   38400         /* console baud rate */
 #endif
-#define K 1024
-#define M 1024*K
-
-;#define RAMSIZE 256*K*4       /* 1 chip 256Kx4 */
-#define  RAMSIZE   4*M*4 * 2   /* 2 chips 4Mx4  */
+#ifndef I2C
+    #define I2C  DRAM_8BIT     /* I2C requires 8 bit DRAM */
+#endif
+#if I2C && !DRAM_8BIT
+  #error "I2C requires 8 bit DRAM (DRAM_8BIT=1)!"
+#endif
 
-#define EM_Z80 1               /* Emulate Z80 if true */
+#define EM_Z80 1               /* Emulate Z80 if true, else 8080 */
 
 #ifndef FAT16_SUPPORT
   #define FAT16_SUPPORT 1      /* Include Support for FAT16 Partitions */
 #define        RXBUFSIZE 128           /* USART recieve buffer size. Must be power of 2 */
 #define        TXBUFSIZE 128           /* USART transmit buffer size. Must be power of 2 */
 
+#define I2C_CLOCK  100000      /* 100kHz */
+#define I2C_BUFSIZE    17      /* largest message size including address byte (SLA) */
 
-#if EM_Z80
-  #define CPUSTR "Z80"
-#else
-  #define CPUSTR "8080"
-#endif
 
 .equ BOOTWAIT      = 1
 .equ MEMTEST       = 1
 #define DBG_TRACE_BOTTOM 0x01  /* Page boundaries for INS_DEBUG and PRINT_PC  */
 #define DBG_TRACE_TOP   0xdc   /* Trace is off, below bottom page and above top page. */
 
+#if EM_Z80
+  #define CPUSTR "Z80"
+#else
+  #define CPUSTR "8080"
+#endif
+
 ;-----------------------------------------------------------------------
 ; Port declarations
 
 #define startTraceCmd 1
 #define stopTraceCmd  0
 
+; Virtual I2C Interface
+#define I2CSTAT        0x05
+#define I2CCTRL        0x05
+#define I2CBLEN        0x06
+#define I2CADR 0x07
+#define I2CADRL        0x07
+#define I2CADRH        0x08
+
+; Port-Expander PCF8574
+#define PORT   0x80
+#define PORT0  0x80
+#define PORT1  0x81
+#define PORT2  0x82
+#define PORT3  0x83
+#define PORT4  0x84
+#define PORT5  0x85
+#define PORT6  0x86
+#define PORT7  0x87
+
 
 #if defined __ATmega8__
 .equ   RXTXDR0 = UDR
 
 ; vim:set ts=8 noet nowrap
 
-
diff --git a/avr/i2c.asm b/avr/i2c.asm
new file mode 100644 (file)
index 0000000..4932173
--- /dev/null
@@ -0,0 +1,477 @@
+; I2C (TWI) master interface. 
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+;
+;    Copyright (C) 2010 Leo C.
+;
+;    This file is part of avrcpm.
+;
+;    avrcpm is free software: you can redistribute it and/or modify it
+;    under the terms of the GNU General Public License as published by
+;    the Free Software Foundation, either version 3 of the License, or
+;    (at your option) any later version.
+;
+;    avrcpm is distributed in the hope that it will be useful,
+;    but WITHOUT ANY WARRANTY; without even the implied warranty of
+;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;    GNU General Public License for more details.
+;
+;    You should have received a copy of the GNU General Public License
+;    along with avrcpm.  If not, see <http://www.gnu.org/licenses/>.
+;
+;    $Id$
+;
+
+#if I2C 
+
+/* General TWI Master status codes */
+#define TWI_START                  0x08  /* START has been transmitted */
+#define TWI_REP_START              0x10  /* Repeated START has been transmitted */
+#define TWI_ARB_LOST               0x38  /* Arbitration lost */
+
+/* TWI Master Transmitter status codes */
+#define TWI_MTX_ADR_ACK            0x18  /* SLA+W has been transmitted and ACK received */
+#define TWI_MTX_ADR_NACK           0x20  /* SLA+W has been transmitted and NACK received */
+#define TWI_MTX_DATA_ACK           0x28  /* Data byte has been transmitted and ACK received */
+#define TWI_MTX_DATA_NACK          0x30  /* Data byte has been transmitted and NACK received */
+
+/* TWI Master Receiver status codes */
+#define TWI_MRX_ADR_ACK            0x40  /* SLA+R has been transmitted and ACK received */
+#define TWI_MRX_ADR_NACK           0x48  /* SLA+R has been transmitted and NACK received */
+#define TWI_MRX_DATA_ACK           0x50  /* Data byte has been received and ACK transmitted */
+#define TWI_MRX_DATA_NACK          0x58  /* Data byte has been received and NACK transmitted */
+
+/* TWI Miscellaneous status codes */
+#define TWI_NO_STATE               0xF8  /* No relevant state information available */
+#define TWI_BUS_ERROR              0x00  /* Bus error due to an illegal START or STOP condition */
+
+
+#define I2C_BR ((F_CPU / (2 * I2C_CLOCK)) - 8) /* I2C Bit Rate */
+
+;----------------------------------------------------------------------
+;
+; TWINT: TWI Interrupt Flag
+; TWEA:  TWI Enable Acknowledge Bit
+; TWSTA: TWI START Condition Bit
+; TWSTO: TWI STOP Condition Bit
+; TWEN:  TWI Enable Bit
+; TWIE:  TWI Interrupt Enable
+; 
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|           (1<<TWEA)
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+; 
+; default:
+;      (1<<TWEN)|          (1<<TWINT)|           (1<<TWSTO)
+; 
+; Init:
+;      (1<<TWEN)
+; 
+; start read/write:
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+;      (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+; 
+; wait ready:
+;       (1<<TWIE)|(1<<TWSTO)
+; 
+;----------------------------------------------------------------------
+
+       .dseg
+
+i2c_var:
+i2ci_idx:
+       .byte   1
+i2c_result:
+       .byte   1
+i2c_bufcnt:
+       .byte   1
+i2c_buf:
+       .byte   I2C_BUFSIZE
+
+       .equ oi2ci_idx   = 0
+       .equ oi2c_result = 1
+       .equ oi2c_bufcnt = 2
+       .equ oi2c_buf    = 3
+
+;------------------------------------------------------------------
+
+       .cseg
+
+
+       INTERRUPT TWIaddr
+       
+       push    temp
+       in      temp,sreg
+       push    temp
+       push    temp2
+       push    zh
+       push    zl
+
+       ldiw    z,i2c_var
+       ldd     temp2,z+oi2ci_idx                       
+
+       inm8    temp,TWSR
+
+       cpi     temp,TWI_START
+       breq    i2ci_START
+       cpi     temp,TWI_REP_START
+       breq    i2ci_REP_START
+       cpi     temp,TWI_MTX_ADR_ACK
+       breq    i2ci_MTX_ADR_ACK
+       cpi     temp,TWI_MTX_DATA_ACK
+       breq    i2ci_MTX_DATA_ACK
+       cpi     temp,TWI_MRX_ADR_ACK
+       breq    i2ci_MRX_ADR_ACK
+       cpi     temp,TWI_MRX_DATA_ACK
+       breq    i2ci_MRX_DATA_ACK
+       cpi     temp,TWI_MRX_DATA_NACK
+       breq    i2ci_MRX_DATA_NACK
+       rjmp    i2ci_default
+
+i2ci_START:
+i2ci_REP_START:
+       clr     temp2                                   ;reset buffer pointer
+i2ci_MTX_ADR_ACK:
+i2ci_MTX_DATA_ACK:
+       ldd     temp,z+oi2c_bufcnt
+       cp      temp2,temp                              
+       brsh    i2ci_12
+       add     zl,temp2
+       adc     zh,_0
+       inc     temp2
+       ldd     temp,z+oi2c_buf
+       outm8   TWDR,temp
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+       rjmp    i2ci_end
+
+i2ci_12:
+       std     z+oi2c_result,_255
+       rjmp    i2ci_default
+
+i2ci_MRX_DATA_ACK:
+       add     zl,temp2
+       adc     zh,_0
+       inc     temp2
+       inm8    temp,TWDR
+       std     z+oi2c_buf,temp
+i2ci_MRX_ADR_ACK:
+       lds     temp,i2c_bufcnt
+       dec     temp
+       cp      temp2,temp
+       brsh    i2ci_32
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)
+       rjmp    i2ci_end
+i2ci_32:
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+       rjmp    i2ci_end
+
+i2ci_MRX_DATA_NACK:
+       std     z+oi2c_result,_255                      ;result = 1
+       add     zl,temp2
+       adc     zh,_0
+       inm8    temp,TWDR
+       std     z+oi2c_buf,temp
+;      fall thru
+
+i2ci_default:
+       ldi     temp,(1<<TWEN)|(1<<TWINT)|(1<<TWSTO)
+
+i2ci_end: 
+       outm8   TWCR,temp
+       sts     i2ci_idx,temp2
+       pop     zl
+       pop     zh
+       pop     temp2
+       pop     temp
+       out     sreg,temp
+       pop     temp
+       reti
+
+;------------------------------------------------------------------
+
+i2c_init:
+       ldi     temp,I2C_BR
+       outm8   TWBR,temp
+       outm8   TWDR,_255                       ;
+       ldi     temp,(1<<TWEN)                  ;Enable TWI, disable Interupts.
+       outm8   TWCR,temp
+
+       ldi     temp,1
+       sts     i2c_result,temp
+       ret
+
+;------------------------------------------------------------------
+
+i2c_waitready:
+       push    temp
+i2c_b:
+       inm8    temp,TWCR
+       andi    temp,(1<<TWIE)|(1<<TWSTO)
+       brne    i2c_b
+       pop     temp
+       ret
+
+;------------------------------------------------------------------
+;
+;      z:      Pointer to the data to write.
+;              First byte is slave address
+;      temp2:  Number of bytes to write including address byte.
+;
+
+i2c_write:
+       rcall   i2c_waitready
+
+       push    zh
+       push    zl
+       push    xh
+       push    xl
+
+#if 0
+       rcall   printstr
+       .db     '\r', 'W', 0,0
+       mov     temp,temp2
+       rcall   printhex
+       rcall   printstr
+       .db     ": ", 0,0
+       rcall   dbg_hexdump_line
+#endif
+
+       ldiw    x,i2c_result
+       st      x+,_0                           ;result = 0
+       st      x+,temp2                        ;store size
+       ld      temp,z+
+       cbr     temp,0x01
+i2c_wl:
+       st      x+,temp
+       dec     temp2
+       breq    i2c_wle
+       ld      temp,z+
+       rjmp    i2c_wl
+i2c_wle:
+       ; Enable TWI, TWI int and initiate start condition
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+       outm8   TWCR,temp
+
+       pop     xl
+       pop     xh
+       pop     zl
+       pop     zh
+       ret
+
+
+;------------------------------------------------------------------
+;
+;      z:      Pointer to data buffer.
+;              First byte of buffer is slave address
+;      temp2:  Number of bytes to write including address byte.
+;
+;      temp:   return (fail = 0, else succsess)
+
+i2c_read:
+       rcall   i2c_waitready
+
+       push    zh
+       push    zl
+       push    xh
+       push    xl
+       ldiw    x,i2c_result
+       st      x+,_0                           ;result = 0
+       st      x+,temp2                        ;store size
+       ld      temp,z
+       sbr     temp,0x01
+       st      x,temp
+
+       ; Enable TWI, TWI int and initiate start condition
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+       outm8   TWCR,temp
+
+       rcall   i2c_waitready
+
+#if 0
+       rcall   printstr
+       .db     '\r', 'R', 0,0
+       mov     temp,temp2
+       rcall   printhex
+       rcall   printstr
+       .db     ": ", 0,0
+#endif
+
+       lds     temp,i2c_result
+       tst     temp
+       breq    i2c_ex                          ;
+i2c_rl:
+       ld      temp,x+
+       st      z+,temp
+       dec     temp2
+       brne    i2c_rl
+
+i2c_ex:
+       lds     temp,i2c_result
+       pop     xl
+       pop     xh
+       pop     zl
+       pop     zh
+#if 0
+       rcall   dbg_hexdump_line
+#endif
+       ret
+
+;------------------------------------------------------------------
+
+       .dseg
+
+vi2c_stat:
+       .byte   1
+vi2c_blen:
+       .byte   1
+vi2c_addr:
+       .byte   2
+
+       .cseg
+
+vi2c_stat_get:
+       lds     temp,vi2c_stat
+       ret
+
+vi2c_param_get:
+       ldiw    z,vi2c_blen
+       add     zl,temp3
+       adc     zh,_0
+       ld      temp,z
+       ret
+
+vi2c_param_set:
+       ldiw    z,vi2c_blen
+       add     zl,temp3
+       adc     zh,_0
+       st      z,temp
+       ret
+
+;------------------------------------------------------------------
+;
+;      x:      Pointer to the data buffer.
+;              First byte is slave address
+;      temp3:  Number of bytes to write including address byte.
+;
+
+vi2c_read:
+       rcall   i2c_waitready
+
+       ldiw    z,i2c_var
+       std     z+oi2c_result,_0                ;result = 0
+       lds     temp3,vi2c_blen
+       std     z+oi2c_bufcnt,temp3             ;store size
+       adiw    z,oi2c_buf
+       ldsw    x,vi2c_addr
+       lcall   dram_read_pp
+       sbr     temp,0x01
+       st      z+,temp
+       dec     temp3
+
+       ; Enable TWI, TWI int and initiate start condition
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+       outm8   TWCR,temp
+
+       rcall   i2c_waitready
+
+       lds     temp,i2c_result
+       tst     temp
+       breq    vi2c_ex                         ;
+vi2c_rl:
+       ld      temp,z+
+       lcall   dram_write_pp
+       dec     temp3
+       brne    vi2c_rl
+
+vi2c_ex:
+       ret
+
+;------------------------------------------------------------------
+;
+;      x:      Pointer to the data to write.
+;              First byte is slave address
+;      temp2:  Number of bytes to write including address byte.
+;
+
+vi2c_write:
+       rcall   i2c_waitready
+       ldiw    z,i2c_var
+       std     z+oi2c_result,_0                ;result = 0
+       lds     temp3,vi2c_blen
+       std     z+oi2c_bufcnt,temp3             ;store size
+       adiw    z,oi2c_buf
+       ldsw    x,vi2c_addr
+       lcall   dram_read_pp
+       cbr     temp,0x01
+vi2c_wl:
+       st      z+,temp
+       dec     temp3
+       breq    vi2c_wle
+       lcall   dram_read_pp
+       rjmp    vi2c_wl
+vi2c_wle:
+       ; Enable TWI, TWI int and initiate start condition
+       ldi     temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+       outm8   TWCR,temp
+
+       ret
+
+
+vi2c_ctrl:
+       cpi     temp,1
+       brne    vi2c_c1
+       rcall   vi2c_read
+       rjmp    vi2c_ce0
+vi2c_c1:
+       cpi     temp,2
+       breq    vi2c_c2
+       ldi     temp,0xff
+       rjmp    vi2c_ce
+vi2c_c2:
+       rcall   vi2c_write
+vi2c_ce0:
+       lds     temp,i2c_result
+       com     temp
+vi2c_ce:
+       sts     vi2c_stat,temp
+       ret
+
+;------------------------------------------------------------------
+
+
+pcf8574_in:
+       ; make a buffer on stack
+       push    _255                    ;place holder for input value
+       in      zh,sph
+       in      zl,spl
+       ldi     temp,0x20               ;pcf8574 address (7 bit)
+       add     temp,temp3
+       lsl     temp
+       push    temp                    ;slave address
+       ldi     temp2,2
+       rcall   i2c_read
+       pop     temp                    ;remove slave address from stack
+       pop     temp                    ;return input value
+       ret
+
+pcf8574_out:
+       ; make a buffer on stack
+       push    temp                    ;output value
+       in      zh,sph
+       in      zl,spl
+       ldi     temp,0x20               ;pcf8574 address (7 bit)
+       add     temp,temp3
+       lsl     temp
+       push    temp                    ;slave address
+       ldi     temp2,2
+       rcall   i2c_write
+       pop     temp                    ;remove buffer from stack
+       pop     temp                    ;
+       ret
+
+
+#endif /* I2C */
+;------------------------------------------------------------------
+; vim:set ts=8 noet nowrap
+
index 914f399589219703ce5bf0ded3f1669c3b2f3aed..37b5a2209681252b92c8a0104d125abd6260d893 100644 (file)
@@ -85,7 +85,6 @@ clr_l:
        cpc     zh,temp2
        brne    clr_l
 
-
 ; Init clock/timer system
 
 ; Init timer 1 as 1 ms system clock tick.
@@ -120,6 +119,11 @@ clr_l:
 
        sei
 
+#if I2C
+       rcall   i2c_init                        ; Init I2C master
+       rcall   rtc_get
+#endif
+
 
 .if BOOTWAIT
        ldi temp,10
index 80e9fca44fafaa6077b007cc9a4d91a1ed87f9d8..fa2b31f846ebe5cd85f13d7691ce7ebc7d146d21 100644 (file)
@@ -47,9 +47,9 @@ timer_top:
 .equ timerofs  = cnt_1ms-timer_ms
  
 clk_out:
-       .byte   6       ;
+       .byte   7       ;
 clock:
-       .byte   6       ;Format (bin): Y M D H M S
+       .byte   7       ;Format (bin): s m h D M YY
 .equ clkofs    = clock-clk_out
 
        .cseg   
@@ -72,11 +72,11 @@ clock:
        outm8   OCR1BL,zl
        
 #if DRAM_8BIT  /* Implies software uart */
-       lds     zl,srx_char_to
+       lds     zl,srx_char_to                  ;try to decrement character timout
        subi    zl,1
-       brcs    syscl0
-       sts     srx_char_to,zl
-       brne    syscl0
+       brcs    syscl0                          ;timer was 0 before (not running)
+       sts     srx_char_to,zl                  ;timer is running, store new value
+       brne    syscl0                          
        rcall   srx_to
 syscl0:
 #endif
@@ -89,15 +89,15 @@ syscl_t1n:
        subi    zl,1
        brcs    syscl_t2n
        sts     delay_timer2,zl
-syscl_t2n:     
-       lds     zl,cnt_1ms
+syscl_t2n:
+
+       lds     zl,cnt_1ms                      ;count milli seconds
        lds     zh,cnt_1ms+1
        adiw    z,1
-       
        sts     cnt_1ms,zl
        sts     cnt_1ms+1,zh
-       cpi     zl,low(1000)
-       ldi     zl,high(1000)           ;doesn't change flags
+       cpi     zl,low(1000)                    ;one second ?
+       ldi     zl,high(1000)                   ;doesn't change flags
        cpc     zh,zl
        brge    syscl_utime
        rjmp    syscl_end
@@ -123,55 +123,61 @@ syscl_utime:
        sts     uptime+3,zl
 
 syscl_clk:
-       lds     zl,clock+5              ;sec
+       lds     zl,clock+0              ;sec
        inc     zl
-       sts     clock+5,zl
+       sts     clock+0,zl
        cpi     zl,60
        brlo    syscl_end
-       sts     clock+5,_0
-       lds     zl,clock+4              ;min
+       sts     clock+0,_0
+       lds     zl,clock+1              ;min
        inc     zl
-       sts     clock+4,zl
+       sts     clock+1,zl
        cpi     zl,60
        brlo    syscl_end
-       sts     clock+4,_0
-       lds     zl,clock+3              ;hour
+       sts     clock+1,_0
+       lds     zl,clock+2              ;hour
        inc     zl
-       sts     clock+3,zl
+       sts     clock+2,zl
        cpi     zl,24
-       brlo    syscl_end
-       sts     clock+3,_0
+       brsh    syscl_clk_date
+       rjmp    syscl_end
+
+syscl_clk_date:
+       sts     clock+2,_0
        push    temp
 
        ldiw    z,dayspm_tab*2 - 1
-       lds     temp,clock+1            ;month
+       lds     temp,clock+4            ;month
        add     zl,temp
        adc     zh,_0
        lpm     zh,z                    ;days this month
        cpi     temp,2
-       brne    syscl_clknf             ;february, may be leap year
-       lds     zl,(clock+0)            ;year
-       andi    zl,0xfc
+       brne    syscl_clknl             ;february, may be leap year
+       lds     zl,(clock+5)            ;year
+       andi    zl,0x03
        brne    syscl_clknl
        inc     zh                      ;leap year 
 syscl_clknl:
-syscl_clknf:
-       lds     zl,clock+2              ;day
+       lds     zl,clock+3              ;day
        inc     zl
-       sts     clock+2,zl
+       sts     clock+3,zl
        cp      zh,zl
        brsh    syscl_clke
        ldi     zl,1
-       sts     clock+2,zl
+       sts     clock+3,zl
        inc     temp                    ;month
-       sts     clock+1,temp
+       sts     clock+4,temp
        cpi     temp,13
        brlo    syscl_clke
 
-       sts     clock+1,zl
-       lds     zl,clock+0              ;year
+       sts     clock+4,zl
+       lds     zl,clock+5              ;low year
        inc     zl
-       sts     clock+0,zl
+       sts     clock+5,zl
+       brne    syscl_clke
+       lds     zl,clock+6              ;high year
+       inc     zl
+       sts     clock+6,zl
 
 syscl_clke:
        pop     temp
@@ -204,65 +210,318 @@ dly_loop:
 
 ; ----------------------------------------------
 ; 
-
 clockget:
-       ldi     temp,0xFF
-       subi    temp2,CLOCKPORT
-       brcs    clkget_end              ;Port number in range?
        ldiw    z,clk_out
+       tst     temp3
        breq    clkget_copy             ;lowest byte requestet, latch clock
-       cpi     temp2,6
-       brsh    clkget_end              ;Port number to high?
        
-       add     zl,temp2
+       add     zl,temp3
        adc     zh,_0
        ld      temp,z
 clkget_end:
        ret
        
-                       
+
 clkget_copy:
-       ldi     temp2,6
+       ldi     temp3,7
        cli
 clkget_l:
        ldd     temp,z+clkofs
        st      z+,temp
-       dec     temp2
+       dec     temp3
        brne    clkget_l
        sei
+
+       ld      temp2,-z
+       ld      temp, -z
+       rcall   binbcd4
+       std     z+0,temp
+       std     z+1,temp2
+       ldi     temp3,5
+clkget_l2:
+       ld      temp,-z 
+       rcall   binbcd2
+       st      z,temp
+       dec     temp3
+       brne    clkget_l2
+
        lds     temp,clk_out
-                                       ;req. byte in temp
-       ret
+       ret                             ;req. byte in temp
 
+; ----------------------------------------------
+; 
 clockput:
-       subi    temp2,CLOCKPORT
-       brcs    clkput_end              ;Port number in range?
-
        ldiw    z,clk_out
-       breq    clkput_copy             ;lowest byte requestet, latch clock
-       cpi     temp2,6
-       brsh    clkput_end              ;Port number to high?
-       
-       add     zl,temp2
+       add     zl,temp3
        adc     zh,_0
        st      z,temp
+       tst     temp3
+       breq    clkput_copy             ;lowest byte stored, latch clock
 clkput_end:
-       ldiw    z,clk_out
        ret
                
+
 clkput_copy:
-       st      z,temp
-       ldi     temp2,6
+       ldi     temp3,5
+clkput_l2:
+       ld      temp,z  
+       rcall   bcdbin2
+       st      z+,temp
+       dec     temp3
+       brne    clkput_l2
+
+       ldd     temp,z+0
+       ldd     temp2,z+1
+       rcall   bcdbin4
+       st      z+,temp
+       st      z+,temp2
+
+       ldi     temp3,7
        cli
 clkput_l:
-       ld      temp,z+
-       std     z+clkofs-1,temp
-       dec     temp2
+       ld      temp,-z
+       std     z+clkofs,temp
+       dec     temp3
        brne    clkput_l
        sei
-       ldiw    z,clk_out
+#if I2C
+       rcall   rtc_set                 ; set hardware clock
+#endif
+       ret
+
+
+; ----------------------------------------------
+
+; convert binary to bcd
+; (only range 0 - 99)
+
+binbcd2:
+       push    temp2
+       ldi     temp2,10
+       mov     _tmp0,_255
+tobcd_l:
+       inc     _tmp0
+       sub     temp,temp2
+       brcc    tobcd_l
+       add     temp,temp2
+       swap    _tmp0
+       add     temp,_tmp0
+       pop     temp2
+       ret
+       
+
+binbcd4:
+       ldi     temp3,16
+       mov     _tmp0,temp
+       mov     _tmp1,temp2
+       clr     temp
+       clr     temp2
+binbcd4l:
+       lsl     _tmp0
+       rol     _tmp1
+       rol     temp
+       rol     temp2
+       dec     temp3
+       breq    binbcd4e
+
+       subi    temp2,-0x03
+       sbrs    temp2,3
+       subi    temp2,0x03
+       subi    temp2,-0x30
+       sbrs    temp2,7
+       subi    temp2,0x30
+       subi    temp,-0x03
+       sbrs    temp,3
+       subi    temp,0x03
+       subi    temp,-0x30
+       sbrs    temp,7
+       subi    temp,0x30
+       rjmp    binbcd4l
+
+binbcd4e:
+       ret
+
+; convert bcd to binary
+
+bcdbin2:
+       push    temp2
+       mov     temp2,temp              ;temp2 = high digit
+       swap    temp2
+       andi    temp2,0x0f
+       andi    temp,0x0f               ;temp  = low digit
+       mov     _tmp0,temp2
+       ldi     temp2,10
+       mul     temp2,_tmp0             ;high digit * 10
+       add     temp,_tmp0              ;high digit * 10 + low digit
+       pop     temp2
+       ret
+
+bcdbin4:
+       rcall   bcdbin2
+       push    temp
+       mov     temp,temp2
+       rcall   bcdbin2
+       ldi     temp2,100
+       mul     temp,temp2
+       pop     temp
+       mov     temp2,_tmp1
+       add     temp,_tmp0
+       adc     temp2,_0
        ret
 
+
+#if I2C
+
+; ----------------------------------------------
+; Set software clock from hardware clock
+
+rtc_get:
+       push    _0                      ;Placeholder for month/weekday
+       push    _0                      ;day/year
+       push    _0                      ;hours
+       push    _0                      ;minutes
+       ldi     temp,0x10               ;register address
+       push    temp                    ;save reg adr/placeholder for sec
+       in      zh,sph
+       in      zl,spl
+       ldi     temp,0xA0               ;PCF8583 slave address
+       push    temp
+
+       ldi     temp2,2
+       rcall   i2c_write
+       ldi     temp2,3
+       rcall   i2c_read                ;get year (stored in RTC-RAM addr. 10h)
+       tst     temp
+       breq    rtc_get_e
+
+       ldd     temp3,z+1               ;save year
+       ldd     temp4,z+2
+
+       ldi     temp2,2                 ;register pointer. 2 = secs
+       std     z+1,temp2
+       rcall   i2c_write
+       ldi     temp2,6
+       rcall   i2c_read
+       tst     temp
+       breq    rtc_get_e
+
+       ldd     temp,z+4                ;get year
+       rol     temp
+       rol     temp
+       rol     temp
+       eor     temp,temp3
+       andi    temp,0x03
+       breq    rtc_get_1
+       inc     temp3
+       adc     temp4,_0
+rtc_get_1:
+       ldiw    x,clock
+       cli
+
+       ldd     temp,z+1                ;get seconds
+       rcall   bcdbin2
+       st      x+,temp
+       ldd     temp,z+2                ;get minutes
+       rcall   bcdbin2
+       st      x+,temp
+       ldd     temp,z+3                ;get hours
+       rcall   bcdbin2
+       st      x+,temp
+       ldd     temp,z+4                ;get day
+       andi    temp,0x3f
+       rcall   bcdbin2
+       st      x+,temp
+       ldd     temp,z+5                ;get months
+       andi    temp,0x1f
+       rcall   bcdbin2
+       st      x+,temp                 ;store month
+       st      x+,temp3                ;store year
+       st      x+,temp4                ;store year century
+       sei
+
+rtc_get_e:
+       pop     temp
+       pop     temp
+       pop     temp
+       pop     temp
+       pop     temp
+       pop     temp
+       ret
+
+;----------------------------------------------
+; Set hardware clock from software clock
+; 
+; Register:    temp2:  s
+;              temp3:  m
+;              temp4:  h
+;              xl:     D
+;              temp:   M
+;              yl:     Yl
+;              yh:     Yh
+
+rtc_set:
+       ldiw    z,clock
+       cli
+       ldd     temp2,z+0               ;sec
+       ldd     temp3,z+1               ;min
+       ldd     temp4,z+2               ;hours
+       ldd     xl,z+3                  ;day
+       ldd     temp,z+4                ;month
+       ldd     yl,z+5                  ;yearl
+       ldd     yh,z+6                  ;yearh
+       sei
+       rcall   binbcd2
+       push    temp                    ;-1 save month
+       mov     temp,xl
+       rcall   binbcd2
+       mov     xl,yl                   ;   least significant 2 bits of year
+       swap    xl
+       lsl     xl
+       lsl     xl
+       andi    xl,0xc0
+       or      temp,xl                 ;   combine with day
+       push    temp                    ;-2 save year/day
+       mov     temp,temp4
+       rcall   binbcd2
+       push    temp                    ;-3 save hours
+       mov     temp,temp3
+       rcall   binbcd2
+       push    temp                    ;-4 save min
+       mov     temp,temp2
+       rcall   binbcd2
+       push    temp                    ;-5 save sec
+
+       push    _0                      ;-6 1/10s, 1/100s
+       ldi     temp,0x84               ;   stop count, alarm enable
+       push    temp                    ;-7
+       push    _0                      ;-8 register address
+       in      zh,sph
+       in      zl,spl
+       ldi     temp,0xA0               ;   PCF8583 slave address
+       push    temp                    ;(-9)
+
+       ldi     temp2,9
+       rcall   i2c_write
+       ldi     temp,0x04               ;enable counting
+       std     z+2,temp
+       ldi     temp2,3
+       rcall   i2c_write
+       std     z+3,yh                  ;store year in RTC RAM
+       std     z+2,yl
+       ldi     temp,0x10
+       std     z+1,temp
+       ldi     temp2,4
+       rcall   i2c_write
+
+       addiw   z,8                     ;remove buffer from stack
+       cli
+       out     spl,zl
+       sei
+       out     sph,zh
+
+       ret
+#endif
+
 ; ----------------------------------------------
 ; 
 
index 94327aae35679fd7fafa0fc7bc4300a26863e710..b03a268fdbf07387492f4b1a6520974ea56e16fc 100644 (file)
 ;03    3       in      - "UART" status: bit 0 = rx, bit 1 = tx
 ;04    4       in      - "UART" data register, no wait
 ;
+;------------------------ Virtual I2C interface --------------------------
+;05    5       out     - Control Port: 1 = Start read operation
+;                                      2 = Start write operation 
+;05    5       in      - Status of last Transfer: 0 = ok, else fail
+;06    6       in/out  - Number of bytes to transfer, including Slave address
+;07,08 7,8     in/out  - Read/Write address low/high
+;
+;------------------------ Disk I/O ---------------------------------------
 ;0D,0E 13,14   in/out  - Set address of Bios Controll Block
 ;0F    15      in/out  - Disk select
 ;10,11  16,17  in/out  - Track select
 ;16    22      in      - Result of last read/write operation.
 ;                        0x00 = ok, 0xff = error (--> Bad Sector)
 ;
+;
+;
+;------------------------ Wall Clock and Timers --------------------------
 ;40    64-71   in/out  - Timer/Clock control.  
 ;41-46
 ;
-;47-4C         clock   - Binary format: y, m, d, h, m, s
+;47-4D         clock   - BCD format: ss, mm, hh,  DD, MM, YYl, YYh
+;
+;------------------------ Ports ------------------------------------------
+;80-87         in/out  - Port-Expander PCF8574 (max. 8 Chips)
+;88-8F         in/out  - Port-Expander PCF8574A (not implemented yet!)
 
 
 ; ---------------------------------------------- Start of Code Segment
@@ -89,13 +104,28 @@ vport_tbl:
        .dw     utimeget
        .dw     utimeput
 
-       .db     CLOCKPORT,6     ;Clock format (bin): y, m, d, h, m, s
+       .db     CLOCKPORT,7     ;Clock format (bcd): ss, mm, hh,  DD, MM, YYl, YYh
        .dw     clockget
        .dw     clockput
 
        .db     DEBUGPORT,1
        .dw     dbg_stat
        .dw     dbg_ctrl
+
+#if I2C
+       .db     I2CCTRL,1
+       .dw     vi2c_stat_get
+       .dw     vi2c_ctrl
+
+       .db     I2CBLEN,3       ;
+       .dw     vi2c_param_get
+       .dw     vi2c_param_set
+
+       .db     PORT,8
+       .dw     pcf8574_in
+       .dw     pcf8574_out
+#endif
+
        .db     0,0             ; Stop mark
 
 ;---------------------------------------------------------------------
@@ -147,8 +177,8 @@ vprw_next:                  ;port # not in range, test next block.
        adiw    z,4
        rjmp    vprw_loop
 vprw_found:
-       brtc    PC+2
-       adiw    z,2
+       brtc    PC+2            ;read or write?
+       adiw    z,2             ;skip read function pointer
        lpm     _tmp0,z+
        lpm     _tmp1,z+
        movw    z,_tmp0
index 2b3842f600b43a4a568ec0fe3634ba7d5fe0d604..a260ec85b6f9d976c6256026e595182ada085c67 100644 (file)
 \r
        maclib  CFGACPM.LIB\r
 \r
+cr     equ     0dh\r
+lf     equ     0ah\r
+\r
        aseg\r
        org     100h\r
        .phase  bios\r
        .z80\r
 \r
-nsects         equ     ($-ccp)/128     ;warm start sector count\r
+nsects equ     ($-ccp)/128     ;warm start sector count\r
        \r
-       jp boot\r
+       jp      boot\r
 wboote:        \r
-       jp wboot\r
-       jp const\r
-       jp conin\r
-       jp conout\r
-       jp list\r
-       jp punch\r
-       jp reader\r
-       jp home\r
-       jp seldsk\r
-       jp settrk\r
-       jp setsec\r
-       jp setdma\r
-       jp read\r
-       jp write\r
-       jp listst\r
-       jp sectran\r
+       jp      wboot\r
+       jp      const\r
+       jp      conin\r
+       jp      conout\r
+       jp      list\r
+       jp      punch\r
+       jp      reader\r
+       jp      home\r
+       jp      seldsk\r
+       jp      settrk\r
+       jp      setsec\r
+       jp      setdma\r
+       jp      read\r
+       jp      write\r
+       jp      listst\r
+       jp      sectran\r
+       jp      0               ;zsdos (?)\r
+       jp      0               ;zsdos (?)\r
+       jp      0               ;zsdos (?)\r
+       jp      clock           ;zsdos compatible clock set/get\r
+\r
 \r
        .8080\r
        maclib AVRCPM.LIB\r
@@ -92,34 +100,34 @@ msgnodisk:
        db      cr,lf,0\r
 \r
 const:\r
-       in a,(0)\r
+       in      a,(0)\r
        ret\r
 \r
 conin:\r
-       in a,(0)\r
-       cp 0ffh\r
-       jp nz,conin\r
+       in      a,(0)\r
+       cp      0ffh\r
+       jp      nz,conin\r
 \r
-       in a,(1)\r
+       in      a,(1)\r
        ret\r
 \r
 conout:\r
-       ld a,c\r
-       out (1),a\r
+       ld      a,c\r
+       out     (1),a\r
        ret\r
 \r
 list:\r
        ret\r
 \r
 listst:\r
-       ld a,0\r
+       ld      a,0\r
        ret\r
 \r
 punch:\r
        ret\r
 \r
 reader:\r
-       ld a,01Fh\r
+       ld      a,01Fh\r
        ret\r
 \r
 prmsg:\r
@@ -405,6 +413,55 @@ sectran:
        ld h,0\r
        ret\r
 \r
+;------------------------------------------------------------------------\r
+; ZSDOS clock drivers may use registers BC and D without restoring  them, \r
+; but must preserve the Z80's alternate and index registers.  \r
+; Other registers must be used exactly as follows:\r
+;\r
+;   Enter:     C = 00H to Read the Clock, 01H to Set the Clock\r
+;             DE = Address of a 6-byte field to Receive or from which \r
+;                  to Set time in DateStamper format (BCD digits as: \r
+;                  YY MM DD HH MM SS).  24-hour operation is assumed.\r
+;\r
+;   Exit :     A = 01H for a successful operation,\r
+;                  0FFH for a failure of any sort (Can't set, etc.)\r
+;\r
+;            When Reading the Clock:\r
+;              E = Original contents of Entry value of DE plus 5\r
+;             HL = Entry value of DE plus 5 (Seconds field)\r
+\r
+clock:\r
+       dec     c\r
+       jr      z,clk_set\r
+       inc     c\r
+       ret     nz\r
+\r
+clk_read:\r
+       ex      de,hl\r
+       ld      bc,5*256 + CLOCKPORT-1\r
+clkg_l:\r
+       inc     c\r
+       ini\r
+       jr      nz,clkg_l\r
+       ld      e,(hl)\r
+       in      a,(CLOCKPORT+5)\r
+       ld      (hl),a\r
+       jr      clk_e\r
+\r
+clk_set:\r
+       ld      hl,5\r
+       add     hl,de\r
+       ld      bc,6*256 + CLOCKPORT+6\r
+clks_l:\r
+       dec     c\r
+       outd\r
+       jr      nz,clks_l\r
+clk_e:\r
+       ld      a,1\r
+       ret\r
+\r
+;------------------------------------------------------------------------\r
+\r
 bcb:   dw      drvtbl\r
        dw      dirbuf\r
        dw      enddat\r
index 6f30879d7745f1aacd924f31d43eada512634f56..7c2f7d01a1db181053511ab1c20bf50125eca16d 100644 (file)
@@ -29,11 +29,80 @@ iobyte      equ     0003h           ;intel iobyte
 buff   equ     0080h           ;default buffer address\r
 retry  equ     3               ;max retries on disk i/o before error\r
 \r
+\r
+;copy from avr/virt_ports.asm:\r
+;   Port        Direction  Function\r
+;hex   dez\r
+;-------------------------------------------------------------------------\r
+;00    0       in      - Con status. \r
+;                        Returns 0xFF if the UART has a byte, 0 otherwise.\r
+;01    1       in/out  - Console input, aka UDR. / Console Output\r
+;02    2       out     - Console Output (deprecated)\r
+;03    3       in      - "UART" status: bit 0 = rx, bit 1 = tx\r
+;04    4       in      - "UART" data register, no wait\r
+;\r
+;------------------------ Virtual I2C interface --------------------------\r
+;05    5       out     - Control Port: 1 = Start read operation\r
+;                                      2 = Start write operation \r
+;05    5       in      - Status of last Transfer: 0 = ok, else fail\r
+;06    6       in/out  - Number of bytes to transfer, including Slave address\r
+;07,08 7,8     in/out  - Read/Write address low/high\r
+;\r
+;------------------------ Disk I/O ---------------------------------------\r
+;0D,0E 13,14   in/out  - Set address of Bios Controll Block\r
+;0F    15      in/out  - Disk select\r
+;10,11  16,17  in/out  - Track select\r
+;12,13         18,19   in/out  - Sector select\r
+;14,15         20,21   in/out  - Write addr\r
+;              \r
+;16    22      out     - Trigger disk i/o operations\r
+;                        Bit 7 = 1: Read sector\r
+;                        Bit 6 = 1: Write sector\r
+;                        Bit 5 = 1: BIOS WBOOT\r
+;                        Bit 4 = 1: BIOS Home\r
+;                        Only one of bits 4..7  may be set.\r
+;                        If Write function (bit 6=1):\r
+;                         Bits 0..2: 0 - write to allocated\r
+;                                    1 - write to directory\r
+;                                    2 - write unallocated\r
+;                                    3 - write to directory                     \r
+;\r
+;16    22      in      - Result of last read/write operation.\r
+;                        0x00 = ok, 0xff = error (--> Bad Sector)\r
+;\r
+;\r
+;\r
+;------------------------ Wall Clock and Timers --------------------------\r
+;40    64-71   in/out  - Timer/Clock control.  \r
+;41-46\r
+;\r
+;47-4D         clock   - BCD format: ss, mm, hh,  DD, MM, YYl, YYh\r
+;\r
+;------------------------ Ports ------------------------------------------\r
+;80-87         in/out  - Port-Expander PCF8574 (max. 8 Chips)\r
+;88-8F         in/out  - Port-Expander PCF8574A (not implemented yet!)\r
+\r
+\r
 READ_FUNC   equ        7\r
 WRITE_FUNC  equ        6\r
 BOOT_FUNC   equ 5\r
 HOME_FUNC   equ 4\r
 \r
-cr equ 13\r
-lf equ 10\r
+TIMERCTL       equ     040h\r
+TIMER_MSECS    equ     TIMERCTL+1\r
+TIMER_SECS     equ     TIMER_MSECS+2\r
+starttimercmd  equ     1\r
+quitTimerCmd   equ     2\r
+printTimerCmd  equ     15\r
+uptimeCmd      equ     16\r
+\r
+CLOCKPORT      equ     TIMERCTL+7\r
+\r
+DEBUGPORT      equ     04FH\r
+StartTraceCmd  equ     1\r
+StopTraceCmd   equ     0\r
+\r
+\r
+\r
+\r
 \r
index e12e618cd1fea192ee346134f47937832794c890..e60ea576df6c95d137a2bc40ac0de17d40b47c3e 100644 (file)
@@ -37,6 +37,14 @@ CPM.BIN: IPL.BIN BIOS.BIN $(CPMSYS)
        dd conv=sync bs=128  count=7 if=BIOS.BIN >> tmpCPM.BIN &&\
        mv tmpCPM.BIN CPM.BIN
 
+zsdossys: IPL.BIN CCP.BIN ZSDOS.BIN BIOS.BIN
+       dd conv=sync bs=118 count=1  if=IPL.BIN    > tmpCPM.BIN  &&\
+               echo -n "<CPM_Disk>"              >> tmpCPM.BIN  &&\
+       dd conv=sync bs=128 count=16 if=CCP.BIN   >> tmpCPM.BIN  &&\
+       dd conv=sync bs=128 count=28 if=ZSDOS.BIN >> tmpCPM.BIN  &&\
+       dd conv=sync bs=128 count=7  if=BIOS.BIN  >> tmpCPM.BIN  &&\
+       mv tmpCPM.BIN zsdossys
+
 
 BIOS.PRN BIOS.REL : AVRCPM.LIB CFGACPM.LIB
 IPL.PRN IPL.REL : CFGACPM.LIB
@@ -94,6 +102,7 @@ help:
        @echo -e "The following make targets are supported:\n"\
        "    diskimage   - Build a complete CP/M image. (default)\n"\
        "    CPM.BIN     - Build CP/M system (IPL+CCP+BDOS+BIOS).\n"\
+       "    zsdossys    - Build ZSDOS system (IPL+CCP+ZSDOS+BIOS).\n"\
        "\n"\
        "    BIOS.PRN    - Make a listing file from bios.asm\n"\
        "    IPL.PRN     - Dito for ipl\n"\
@@ -106,3 +115,4 @@ help:
        "\n"\
        "    clean       - Remove intermediate and output files.\n"\
        "    help        - Print this message and exit.\n"
+
similarity index 100%
rename from cpm/utils/TIMER.MAC
rename to cpm/utils/ACT.MAC
diff --git a/cpm/utils/AVRCLOCK.MAC b/cpm/utils/AVRCLOCK.MAC
new file mode 100644 (file)
index 0000000..dc506de
--- /dev/null
@@ -0,0 +1,195 @@
+VERS   EQU     02\r
+       .Z80\r
+;      NAME    AVRCLK          ; Change this to no more than 6-char\r
+                               ; name for the REL driver module\r
+\r
+;---------------------------------------------------------------------\r
+; Time format (6 bytes packed BCD)\r
+; \r
+; TIME+0       last 2 digits of year (prefix 19 assumed for 78 to 99, else 20 assumed)\r
+; TIME+1       month [1..12]\r
+; TIME+2       day [1..31]\r
+; TIME+3       hour [0..23]\r
+; TIME+4       minute [0..59]\r
+; TIME+5       second [0..59]\r
+; \r
+\r
+; This first section contains identification information for the driver\r
+; The information is not placed in the clock driver code section, but are\r
+; located in a different area located by the _CLKID Named Common directive.\r
+\r
+       COMMON  /_CLKID/\r
+\r
+DESCST:        DEFW    0000            ; Add label here if a static year byte\r
+                               ; is used by your clock driver.  The\r
+                               ; label should point to the year byte\r
+\r
+               ;123456789012345678901234\r
+CLKNAM:        DEFB    'AVRCPM Clock            '      ; Exactly 24 chars in name\r
+       DEFB    VERS/10+'0','.',VERS MOD 10 +'0',0\r
+\r
+DESCR: DEFB    'This is the AVRCPM clock',0\r
+\r
+\r
+;---------------------------------------------------------------------\r
+; This section contains any configurable parameters needed for the\r
+; clock driver.  They must be structured in the manner shown in order\r
+; for the loader to properly match and set the values.\r
+; The values in this section are not loaded in the same code section\r
+; as the actual driver code, but are located in another base referenced\r
+; by the _PARM_ Named Common directive.\r
+\r
+       COMMON  /_PARM_/\r
+\r
+PARBAS:        DEFW    0               ; # of parameters (Set to 00 if none)\r
+       DEFW    0               ; Pointer to STRS (Set to 00 if none)\r
+\r
+;------------------------------------------------------------------\r
+; This section should contain the actual Clock Driver code, and all\r
+; entries here are located in the CSEG, or Code Segment.\r
+\r
+       CSEG\r
+\r
+MHZ     equ    2               ; Base Processor speed\r
+CLOCKPORT equ  47h\r
+\r
+;-----------------------------------------------------------\r
+;          Z S D O S    C L O C K    H E A D E R\r
+;-----------------------------------------------------------\r
+; Enter: HL points to a 6-byte buffer to Get/Set time\r
+; Exit :  A=1 on Success, A=FFH if error\r
+;       HL points to last char in buffer\r
+;      E contains original seconds (HL+5)\r
+; NOTE: If clock Set is not included, comment these two jumps\r
+;      out to save a few bytes.  The loader, SETUPZST, uses\r
+;      these two jumps to recognize a full ZSDOS clock and\r
+;      modify the interface code.\r
+\r
+PRGBAS:        JP      GETTIM          ; Jump to Read Clock\r
+       JP      WRCLK           ; Jump to Set Clock\r
+\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+;              R e a d    T h e    C l o c k\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+GETTIM:                                ; The work of reading the clock\r
+                               ; goes here.  Values needing to be set\r
+                               ; during installation are referenced as:\r
+       ld      bc,5\r
+       add     hl,bc\r
+       push    hl\r
+       ld      b,6\r
+       ld      c,CLOCKPORT\r
+       ld      e,(hl)\r
+GETT_l:\r
+       in      a,(c)\r
+       ld      (hl),a\r
+       inc     c\r
+       dec     hl\r
+       djnz    GETT_l\r
+       pop     hl\r
+       ld      a,1\r
+       ret\r
+       \r
+\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+;              S e t    T h e    C l o c k\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+WRCLK:\r
+       ld      a,(hl)\r
+       cp      78h\r
+       ld      a,19h\r
+       jr      nc,WRC_1\r
+       ld      a,20h\r
+WRC_1:\r
+       out     (CLOCKPORT+6),a\r
+       ld      b,6\r
+       ld      c,CLOCKPORT+5\r
+WRC_l:\r
+       ld      a,(hl)\r
+       out     (c),a   \r
+       dec     c\r
+       inc     hl\r
+       djnz    WRC_l\r
+       dec     hl\r
+       ld      a,1\r
+       ret\r
+\r
+\r
+;-------------------------------------------------------------\r
+; This code installs configurable items into the clock module\r
+; Enter with DE pointing to the physical base address of the\r
+;       relocatable module.  DE MUST BE USED TO SET VALUES IN\r
+;       THE CSEG PORTION OF CODE!\r
+; NOTE: Code in this section is not added to the actual clock\r
+;      driver, but placed in a different area referenced to\r
+;      the common base _POST_.\r
+\r
+       COMMON  /_POST_/\r
+\r
+; Values in the _PARM_, _POST_ and _PRE_ sections may be loaded\r
+; and saved directly, since their addresses are constant from\r
+; linkage through execution.  Setting or reading values in the\r
+; CSEG must be indirect based on the value in the DE register\r
+; pair.  The following examples show how to access the various\r
+; sections.\r
+;\r
+;      LD      A,(XYR)         ; EXAMPLE - Get byte from _PARM_ directly\r
+;      LD      HL,YYR          ;    "    - Begin offset into CSEG indirectly\r
+;      ADD     HL,DE           ;    "    - HL now addresses relocated loc'n\r
+;      LD      (HL),A          ;    "    - ..so value can be stored\r
+;\r
+; Likewise, 16-bit values must be accessed indirectly, and may use\r
+; the BC register pair as transfer storage.\r
+;\r
+;      LD      BC,(XPORT)      ; EXAMPLE - Get word from _PARM_ directly\r
+;      LD      HL,YPORT1       ;    "    - Begin offset into CSEG indirectly\r
+;      ADD     HL,DE           ;    "    - HL now addresses relocated loc'n\r
+;      LD      (HL),C          ;    "    - ..so value can be saved..\r
+;      INC     HL              ;    "    - ...a byte..\r
+;      LD      (HL),B          ;    "    - ....at a time..\r
+;\r
+;      LD      (YPORT2),BC     ; EXAMPLE - Values can be stored directly into\r
+;                                   "    - other sections such as _PRE_\r
+\r
+       RET             ; This RETURN MUST be present even if no other\r
+                       ; code is included in this section\r
+\r
+\r
+;----------------------------------------------------------------\r
+; This module is executed just prior to installing the module to\r
+;   insure that a valid clock is present\r
+; Enter with DE pointing to base of relocated clock code segment\r
+;---------------------------------------------------------------\r
+; Read clock and wait for seconds to roll - watchdog protected\r
+; Enter with: DE pointing to relocated clock read routine\r
+;      HL pointing to base of high module\r
+\r
+       COMMON  /_PRE_/\r
+\r
+; Optional final setup of the clock module may go here.  Examples of such\r
+; code would be installation-dependant items such as physical RAM location\r
+; for the driver module.  If any code is added here, the DE register pair\r
+; MUST be preserved to properly inter PRECLOCK code (If included).\r
+\r
+;YPORT2        EQU     $+1             ; EXAMPLE - just to show accessing method\r
+;      LD      BC,0000         ;    "    - ..from _POST_ code.\r
+\r
+       INCLUDE PRECLOCK.LIB    ; This section of code merely calls the\r
+                               ; clock and waits an arbitrary period of\r
+                               ; time (>> 1 second) to see if the time\r
+                               ; changes.  It returns an error if not.\r
+       if 0\r
+TSTRD: JR      TSTRD0  ; Jump around address store\r
+\r
+       DEFW    TSTRD   ; Org location of the code\r
+TSTRD0:        SCF\r
+       LD      A,1\r
+       RET\r
+       endif\r
+\r
+\r
+\r
+       END\r
+\1a\r
diff --git a/cpm/utils/RTCDEMO.PAS b/cpm/utils/RTCDEMO.PAS
new file mode 100644 (file)
index 0000000..dfe332d
--- /dev/null
@@ -0,0 +1,294 @@
+program RTCDemo;\r
+{$C- } {Sonst funktioniert 'keypressed' nicht}\r
+\r
+{---------------------------------------------------------------------\r
+        AVRCPM \r
+        Test und Demonstration des I2C-Interface\r
+        I2C Uhrenchip PCF8583 \r
+        Zeit und Datum lesen und schreiben\r
+\r
+        Moegliche Erweiterung (TODO:):\r
+        - Control/Status-Register und Alarmregister lesen/schreiben\r
+        - RAM lesen/schreiben\r
+\r
+        $Id$\r
+----------------------------------------------------------------------}\r
+  \r
+const\r
+  I2CCMD    = 5;        {adr of I2C Command Port (1=read, 2=write)}\r
+  I2CMSGLEN = 6;        {Transferpuffergroesse}\r
+  I2CADRL   = 7;        {Transferpufferadresse low/high}\r
+  I2CADRH   = 8;\r
+\r
+  I2C_CMD_Read  = 1;    {I2C Read Command}\r
+  I2C_CMD_Write = 2;    {I2C Write Command}\r
+\r
+  { TP Delay Loop }\r
+  T100ms = 100;         {20MHz AVR + Config fuer 3 MHz Z80 (TINST)}\r
+  {T100ms = 75;}        {20MHz AVR + Config fuer 4 MHz Z80 (TINST default)}\r
+\r
+type\r
+  I2CBufLen = 0..16;\r
+\r
+  CalTime = record\r
+    sec: 0..59;\r
+    min: 0..59;\r
+    hrs: 0..23;\r
+    day: 1..31;\r
+    month: 1..12;\r
+    year: integer;\r
+  end;\r
+\r
+  DTinput = array [1..3] of integer;\r
+\r
+var\r
+  msgbuf : array[0..16] of Byte;        {TODO: Transferbuffer nicht global}\r
+\r
+  Time : CalTime;\r
+  Done: boolean;\r
+\r
+{---------------------------------------------------------------------\r
+        Debugging: Print 16 byte RAM ab adr \r
+----------------------------------------------------------------------}\r
+procedure hexdump(adr: integer);\r
+var\r
+  i: integer;\r
+  c: byte;\r
+\r
+  function hexdigit(c: byte): char;\r
+  begin\r
+    if c < 10 then\r
+      hexdigit := char(c + $30)\r
+    else\r
+      hexdigit := char(c - 10 + $41);\r
+  end;\r
+\r
+{TODO: print adr }\r
+begin\r
+  for i := 0 to 15 do\r
+  begin\r
+    c := Mem[adr+i];\r
+    write(hexdigit(c shr 4), hexdigit(c and $f), ' ');\r
+  end;\r
+  writeln;\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+        I2C - Routinen\r
+----------------------------------------------------------------------}\r
+procedure i2c_init;\r
+var\r
+  i: integer;\r
+begin\r
+  msgbuf[0] := $A0;     {I2C-Adresse des RTC-Chips}\r
+\r
+  Port[I2CADRH] := Hi(Addr(msgbuf));\r
+  Port[I2CADRL] := Lo(Addr(msgbuf));\r
+end;\r
+\r
+procedure i2c_write(len:Byte);\r
+begin\r
+  Port[I2CMSGLEN] := len;\r
+  Port[I2CCMD] := I2C_CMD_Write;\r
+end;\r
+\r
+procedure i2c_read(len:Byte);\r
+begin\r
+  Port[I2CMSGLEN] := len;\r
+  Port[I2CCMD] := I2C_CMD_Read;\r
+end;\r
+\r
+\r
+function BCDtoBINbyte(i: byte): byte;\r
+begin\r
+  BCDtoBINbyte := (i div 16) * 10 + (i and $F);\r
+end;\r
+\r
+function BINtoBCDbyte(i: byte): byte;\r
+begin\r
+  BINtoBCDbyte := (i div 10) * 16 + (i mod 10);\r
+end;\r
+\r
+procedure ReadRTC(var t: CalTime);\r
+begin\r
+  msgbuf[1] := 2;\r
+  i2c_write(2);\r
+  i2c_read(6);\r
+  with t do\r
+  begin\r
+    sec  := BCDtoBINbyte(msgbuf[1]);\r
+    min  := BCDtoBINbyte(msgbuf[2]);\r
+    hrs  := BCDtoBINbyte(msgbuf[3] and $3F);\r
+  end;\r
+  msgbuf[1] := $10;\r
+  i2c_write(2);\r
+  i2c_read(3);\r
+  with t do\r
+  begin\r
+    day  := BCDtoBINbyte(msgbuf[4] and $3F);\r
+    month:= BCDtoBINbyte(msgbuf[5] and $1F);\r
+    year := msgbuf[1] + 256*msgbuf[2];\r
+    while Lo(year) and $3 <> (msgbuf[4] shr 6) do\r
+      year := year + 1;\r
+  end;\r
+end;\r
+\r
+\r
+procedure WriteRTC(t: CalTime);\r
+begin\r
+  with t do begin\r
+    msgbuf[1] := 1;                   {register address}\r
+    msgbuf[2] := 0;                   {hundredth of sec}\r
+    msgbuf[3] := BINtoBCDbyte(sec);\r
+    msgbuf[4] := BINtoBCDbyte(min);\r
+    msgbuf[5] := BINtoBCDbyte(hrs);\r
+    msgbuf[6] := BINtoBCDbyte(day) + (Lo(year) shl 6);\r
+    msgbuf[7] := BINtoBCDbyte(month); {TODO: weekdays}\r
+  end;\r
+  i2c_write(8);\r
+\r
+  msgbuf[1] := $10;                  {register address}\r
+  with t do begin\r
+    msgbuf[2] := Lo(year);\r
+    msgbuf[3] := Hi(year);\r
+  end;\r
+  i2c_write(4);\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+        Dialog Routinen\r
+----------------------------------------------------------------------}\r
+\r
+procedure PrintTime(t: CalTime);\r
+begin\r
+  with t do             {TODO: Fuehrende '0' statt ' '}\r
+  begin\r
+    write('Zeit: ', hrs:2, ':',min:2, ':',sec:2, '  ',\r
+          'Datum: ', day, '.', month, '.', year);\r
+  end;\r
+end;\r
+\r
+procedure PrintMenu;\r
+begin\r
+  ClrScr;\r
+  writeln('Menu:');\r
+  writeln(' T) Zeit setzen');\r
+  writeln(' D) Datum setzen');\r
+  writeln(' Q) Quit');\r
+  writeln('> ');\r
+end;\r
+\r
+function GetKey: char;\r
+var\r
+  c: char;\r
+begin\r
+  Read(Kbd, c);\r
+  GetKey := c;\r
+end;\r
+\r
+{Daemliche input routine ohne Fehlerpruefung (TODO:)}\r
+procedure GetDateTime(var a: DTinput; sep: char);\r
+var\r
+  line: String[80];\r
+  s: String[4];\r
+  i,j,k: integer;\r
+  rc: integer;\r
+\r
+begin\r
+  readln(line);\r
+  line := line + sep;\r
+  j := 1;\r
+  for i := 1 to 3 do\r
+  begin\r
+    k := 1;\r
+    while line[k+j] in ['0'..'9'] do\r
+      k := k + 1;\r
+    s := Copy(line, j, k);\r
+    val(s, a[i], rc);\r
+    j := j + k + 1;\r
+  end;\r
+end;\r
+\r
+procedure SetTime;\r
+var\r
+  a: DTinput;\r
+\r
+begin\r
+  write('Zeit (hh:mm:ss): ');\r
+  a[1] := -1;\r
+  GetDateTime(a, ':');\r
+{  writeln('intime:', a[1], ':', a[2], ':', a[3]);\r
+}\r
+  if (a[1] in [0..24]) and (a[2] in [0..59]) and (a[3] in [0..59]) then\r
+  begin\r
+    ReadRTC(Time);\r
+    Time.hrs  := a[1];\r
+    Time.min  := a[2];\r
+    Time.sec  := a[3];\r
+    WriteRTC(Time);\r
+  end else\r
+  begin\r
+    writeln('Fehler in Eingabe.');\r
+  end;\r
+end;\r
+\r
+procedure SetDate;\r
+var\r
+  a: DTinput;\r
+\r
+begin\r
+  write('Datum (TT.MM.JJJJ): ');\r
+  a[1] := -1;\r
+  GetDateTime(a, '.');\r
+{  writeln('indate:', a[1], '.', a[2], '.', a[3]);\r
+}\r
+  if (a[1] in [1..31]) and (a[2] in [1..12]) and (a[3] > 0) and (a[3] <= 2076) then\r
+  begin\r
+    ReadRTC(Time);\r
+    Time.day  := a[1];\r
+    Time.month:= a[2];\r
+    Time.year := a[3];\r
+    WriteRTC(Time);\r
+  end else\r
+  begin\r
+    writeln('Fehler in Eingabe.');\r
+  end;\r
+end;\r
+\r
+procedure CleanConsolebuffer;\r
+var\r
+  c: char;\r
+begin\r
+  while keypressed do c := GetKey;\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+        main\r
+----------------------------------------------------------------------}\r
+\r
+begin\r
+  PrintMenu;\r
+  i2c_init;\r
+\r
+  writeln;\r
+  Done := False;\r
+  repeat\r
+    Delay(T100ms);\r
+    ReadRTC(Time);\r
+    GotoXY(35,1); PrintTime(Time); ClrEol;\r
+    gotoXY(2,5);  ClrEol;\r
+\r
+    if keypressed then\r
+    begin\r
+      gotoXY(1,7); ClrEol;\r
+      gotoXY(1,6); ClrEol;\r
+      case UpCase(GetKey) of\r
+       'T': SetTime;\r
+       'D': SetDate;\r
+       'Q': Done := True;\r
+      end;\r
+    end;\r
+  until Done;\r
+  CleanConsolebuffer;\r
+end.\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file