diff --git a/drivers/Makefile b/drivers/Makefile
index a799114..0d24b7e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -55,7 +55,8 @@ C64OBJS=\
 	cbmcharconv.o
 
 C64_OBJS=\
-	c64timer.o \
+	clk_timer.o \
+	c64_cps.o \
 	c64_input.o
 
 A2OBJS=\
@@ -82,11 +83,11 @@ ATROBJS=\
 	atrcharconv.o
 
 ATR_OBJS=\
-	atr_timer.o \
+	clk_timer.o \
 	atr_input.o
 
 ATRXL_OBJS=\
-	atr_timer.xl.o \
+	clk_timer.xl.o \
 	atr_input.xl.o
 
 VIC20OBJS=\
diff --git a/drivers/atr_timer.s b/drivers/atr_timer.s
deleted file mode 100644
index 40ba3b3..0000000
--- a/drivers/atr_timer.s
+++ /dev/null
@@ -1,141 +0,0 @@
-; timer routines
-;
-; the timer should be a 16-bit counter that's incremented by about
-; 1000 units per second. it doesn't have to be particularly accurate.
-
-.include "atari.inc"
-.include "../inc/common.i"
-
-.export timer_init
-.export timer_read
-.export timer_seconds
-
-.import _atexit
-
-
-.bss
-
-current_time_value: .res 2
-current_seconds:    .res 1
-current_jiffies:    .res 1
-timer_freq:         .res 1      ; VBLANK frequency: 50 - PAL, 60 - NTSC
-timer_freq_reciproc:.res 1      ; reciprocal for timer_freq in ms: 20 - PAL, ~17 - NTSC
-
-.data
-
-vbichain: .word 0
-
-
-.code
-
-; reset timer to 0 and install handler
-; inputs: none
-; outputs: none
-timer_init:
-  lda vbichain+1
-  bne @done
-  lda PAL                       ; hardware register describing TV system of GTIA
-  and #$0e                      ; mask out irrelevant bits
-  bne @ntsc
-  ; PAL system
-  lda #50
-  sta timer_freq
-  lda #20
-  sta timer_freq_reciproc
-  bne @system_set
-@ntsc:
-  ; NTSC system
-  lda #60
-  sta timer_freq
-  lda #17
-  sta timer_freq_reciproc
-@system_set:
-  lda #0                        ; initialize time variables
-  sta current_time_value
-  sta current_time_value+1
-  sta current_seconds
-  sta current_jiffies
-  ldax VVBLKI                   ; IMMEDIATE VERTICAL BLANK NMI VECTOR
-  stax vbichain                 ; save old immediate vector
-  ldy #<timer_vbl_handler
-  ldx #>timer_vbl_handler
-  lda #6                        ; STAGE 1 VBI
-  jsr SETVBV                    ; vector to set VBLANK parameters
-@done:
-  ldax #timer_exit
-  jmp _atexit
-
-timer_exit:
-  lda vbichain+1
-  beq @handler_not_installed
-  ldy vbichain
-  ldx vbichain+1
-  lda #6                        ; STAGE 1 VBI
-  jsr SETVBV                    ; vector to set VBLANK parameters
-  lda #0
-  sta vbichain
-  sta vbichain+1
-@handler_not_installed:
-  rts
-
-; read the current timer value
-; inputs: none
-; outputs: AX = current timer value (roughly equal to number of milliseconds since the last call to 'timer_init')
-timer_read:
-  ldax current_time_value
-  rts
-
-; tick over the current timer value - should be called 50 or 60 times per second, depending on the TV system
-; inputs: none
-; outputs: none (all registers preserved, but carry flag can be modified)
-timer_vbl_handler:
-  pha
-  lda timer_freq_reciproc       ; ms per tick
-  clc
-  adc current_time_value
-  sta current_time_value
-  bcc :+
-  inc current_time_value+1
-: inc current_jiffies
-  lda current_jiffies
-  cmp timer_freq                ; full second?
-  bne @done                     ; no, we're done
-  lda #0                        ; yes, increment "seconds" counter
-  sta current_jiffies
-  sed
-  clc
-  lda #$01
-  adc current_seconds
-  cld
-  cmp #$60
-  bne :+
-  lda #$00
-: sta current_seconds
-@done:
-  pla
-  jmp SYSVBV                    ; vector to process immediate VBLANK
-
-timer_seconds:
-  lda current_seconds
-  rts
-
-
-
-;-- LICENSE FOR atr_timer.s --
-; The contents of this file are subject to the Mozilla Public License
-; Version 1.1 (the "License"); you may not use this file except in
-; compliance with the License. You may obtain a copy of the License at
-; http://www.mozilla.org/MPL/
-; 
-; Software distributed under the License is distributed on an "AS IS"
-; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
-; License for the specific language governing rights and limitations
-; under the License.
-; 
-; The Original Code is ip65.
-; 
-; The Initial Developer of the Original Code is Jonno Downes,
-; jonno@jamtronix.com.
-; Portions created by the Initial Developer are Copyright (C) 2009
-; Jonno Downes. All Rights Reserved.  
-; -- LICENSE END --
diff --git a/drivers/c64_cps.s b/drivers/c64_cps.s
new file mode 100644
index 0000000..dbecd6f
--- /dev/null
+++ b/drivers/c64_cps.s
@@ -0,0 +1,13 @@
+; implementation of __clocks_per_sec for C64
+; CC65's C64 runtime library doesn't provide this function
+; this file provides a version in order that clk_timer.s works without 'ifdefs'
+
+.export __clocks_per_sec
+
+.code
+
+__clocks_per_sec:
+  lda #60
+  rts
+
+.end
diff --git a/drivers/clk_timer.s b/drivers/clk_timer.s
new file mode 100644
index 0000000..53a473b
--- /dev/null
+++ b/drivers/clk_timer.s
@@ -0,0 +1,171 @@
+; timer routines
+; this implementation is for Atari and C64.
+; it uses parts of the C runtime library
+;
+; the timer should be a 16-bit counter that's incremented by about
+; 1000 units per second. it doesn't have to be particularly accurate.
+
+.include "../inc/common.i"
+
+.export timer_init
+.export timer_read
+.export timer_seconds
+
+.import   __clocks_per_sec, _clock
+.import   tosumodeax, tosudiveax
+.import   pusheax, incsp4
+.importzp sp, sreg
+
+
+.bss
+
+timer_freq: .res 1      ; VBLANK frequency: 50 - PAL, 60 - NTSC (Atari); always 60 (C64)
+mult_temp:  .res 2      ; temp var for multiplication routines        
+mult_temp_x:.res 1      ; another temp var for multiplication routines        
+
+
+.data
+
+mult: .byte $4C  ; JMP opcode
+      .res 2     ; address
+
+
+.code
+
+; get timer frequency and patch multiplication routine pointer
+; inputs: none
+; outputs: none
+timer_init:
+  jsr __clocks_per_sec
+  sta timer_freq
+  cmp #50
+  beq @timer50
+  lda #<mult17
+  ldx #>mult17
+  bne @timerset                 ; jmp always
+@timer50:
+  lda #<mult20
+  ldx #>mult20
+@timerset:
+  sta mult+1
+  stx mult+2
+  rts
+
+; read the current timer value
+; inputs: none
+; outputs: AX = current timer value in milliseconds
+timer_read      =       mult
+
+; get current seconds clock hand
+; inputs: none
+; outputs: A = seconds hand (in BCD, range $00..$59)
+timer_seconds:
+  jsr _clock                    ; return current tick count in sreg:AX (high:low 16bits)
+  jsr pusheax                   ; push tick count onto stack
+  ldx #0
+  stx sreg
+  stx sreg+1
+  lda timer_freq
+  jsr tosudiveax                ; dividend on stack, divisor in sreg:AX
+  jsr pusheax
+  ldx #0
+  stx sreg
+  stx sreg+1
+  lda #60
+  jsr tosumodeax                ; result modulo 60
+  ; convert to BCD, a poor man's conversion here....
+  cmp #50
+  bcs @rs_50
+  cmp #40
+  bcs @rs_40
+  cmp #30
+  bcs @rs_30
+  cmp #20
+  bcs @rs_20
+  cmp #10
+  bcs @rs_10
+  rts
+@rs_10:
+  sbc #10
+  ora #$10
+  rts
+@rs_20:
+  sbc #20
+  ora #$20
+  rts
+@rs_30:
+  sbc #30
+  ora #$30
+  rts
+@rs_40:
+  sbc #40
+  ora #$40
+  rts
+@rs_50:
+  sbc #50
+  ora #$50
+  rts
+
+
+; get the current tick count, multiply it by 20, and return the lower 16 bits
+; x*20 = x*16 + x*4
+; inputs: none
+; outputs: AX - tick count times 20 ('milliseconds')
+mult20:
+  jsr _clock                    ; return current tick count in sreg:AX (high:low 16bits)
+  stx mult_temp_x               ; remember high byte of lower 16bits
+  asl a
+  rol mult_temp_x
+  asl a
+  rol mult_temp_x
+  sta mult_temp
+  ldx mult_temp_x
+  stx mult_temp+1               ; mult_temp = ticks * 4
+  asl a
+  rol mult_temp_x
+  asl a
+  rol mult_temp_x               ; mult_temp_x:A = 'ticks * 16'
+  clc                           ; AX - tick count * 16, mult_temp - tick count * 4
+  adc mult_temp
+  sta mult_temp
+  lda mult_temp+1
+  adc mult_temp_x
+  tax
+  lda mult_temp
+  rts
+
+
+; get the current tick count, multiply it by 17, and return the lower 16 bits
+; x*17 = x*16 + x
+; inputs: none
+; outputs: AX - tick count times 17 ('milliseconds')
+mult17:
+  jsr _clock                    ; return current tick count in sreg:AX (high:low 16bits)
+  sta mult_temp
+  stx mult_temp+1
+  stx mult_temp_x
+  .repeat 4
+  asl a
+  rol mult_temp_x
+  .endrepeat                    ; mult_temp_x:A = 'ticks * 16'
+  clc
+  adc mult_temp
+  sta mult_temp
+  lda mult_temp+1
+  adc mult_temp_x
+  tax
+  lda mult_temp
+  rts
+
+
+;-- LICENSE FOR clk_timer.s --
+; The contents of this file are subject to the Mozilla Public License
+; Version 1.1 (the "License"); you may not use this file except in
+; compliance with the License. You may obtain a copy of the License at
+; http://www.mozilla.org/MPL/
+; 
+; Software distributed under the License is distributed on an "AS IS"
+; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+; License for the specific language governing rights and limitations
+; under the License.
+; -- LICENSE END --