CIA1 time problem

Started by MIRKOSOFT, July 16, 2010, 12:31 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

MIRKOSOFT

Hi!


I have problem with time of CIA1 ($DC00...)
Attached screenshots has shown time at top right corner, you can see that there's:
first 03:69a
second (minute after) 04:00a
to time 03:60a it sets when I was awaiting 04:00a.
I don't understand why it does these problems.


Here's source code,
routine showtime corrects data for BSOUT
routine tis gets time from 64HDD-RTC (code not included, but properly working) and sets CIA time:

showtime:
   lda $dc0b
   and #128
   cmp #00
   bne pm
   lda #65
   jmp tost
pm:   lda #80
tost:   sta clock.correctly+5
   lda $dc0b
   and #16
   lsr
   lsr
   lsr
   lsr
   adc #$30
   sta clock.correctly
   lda $dc0b
   and #$0f
   adc #$30
   sta clock.correctly+1
   lda $dc0a
   lsr
   lsr
   lsr
   lsr
   adc #$30
   sta clock.correctly+3
   lda $dc0a
   and #$0f
   adc #$30
   sta clock.correctly+4
   lda #58
   sta clock.correctly+2
   lda $dc08
   jsr clock.possh
   rts


tis:   lda clock.correctly+1   // H-AP-lo
   sbc #$30
   sta clock.low
   lda clock.correctly   // H-AP-hi
   sbc #$30
   cmp #00
   beq nula
   cmp #01
   beq ten
   cmp #02
   beq two
   rts
two:   lda #20
sett:   sta clock.pridat
   lda clock.low
   adc clock.pridat
   sta clock.hour
   jmp cont
ten:   lda #10
   jmp sett
nula:    lda #00
   jmp sett
cont:   lda clock.correctly+3   // M-hi
   sbc #$30
   asl
   asl
   asl
   asl
   sta clock.minute
   lda clock.correctly+4   // M-lo
   sbc #$30
   adc clock.minute
   sta clock.minute
   lda clock.hour
   cmp #13
   bmi am
   sbc #12
   cmp #10
   bmi men
   lda #144
hrst:   sta clock.low
   lda clock.correctly+1
   sbc #$30
   adc clock.low
   sta clock.hour
   lda clock.hour
   ldx clock.minute
   sta $dc0b
   stx $dc0a
   lda #00
   sta $dc08
   rts
men:   lda #128
   jmp hrst
am:   cmp #10
   bmi nine
   lda #16
   jmp hrst
nine:   lda #00
   jmp hrst


It seems that it has any 20 minute cycle, for explaining at 3:29 it skips to 3:20 and 8 minutes later to 3:38...

Is problem in code? Is problem with displaying time?


If anybody can help, please... and many many thanks for every reply....


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

LokalHorst

hello again,
as I don't know where to start, I'll begin with the most obvious 'bugs':
this -
   lsr
   lsr
   lsr
   lsr    <- sets carry if the lo bcd-nibble is 8 or 9
   adc #$30  <- then add with carry
simply change every occurence of the obove to: ORA #$30
...
similar wrong code here:
tis:   lda clock.correctly+1   // H-AP-lo
   sbc #$30  <- AND #$0f see below
   sta clock.low
   lda clock.correctly   // H-AP-hi
   sbc #$30  <- sub with carry w/o sec first -> change to AND #$0f
   cmp #00
   ...
and here (getting worse):
cont:   lda clock.correctly+3   // M-hi
   sbc #$30 <- ??? you shift out the upper ascii-nibble with the following 4 ASL's
   -> remove the above line
   asl
   asl
   asl
   asl
   sta clock.minute
   lda clock.correctly+4   // M-lo
   sbc #$30 <- again sub with carry w/o sec -> change to AND #$0f
   adc clock.minute

you can simplify & give your code more structure by writing 2 small subs:

BCD2ASC: ;input a = packed BCD, output ASCII (buffer)
PHA
LSR
LSR
LSR
LSR
ORA #$30
STA ASCBUF,Y ;tenth's
INY
PLA
AND #$0F
ORA #$30
STA ASCBUF,Y ;one's
RTS

ASC2BCD: ;input ASCII (Buffer), output BCD (TOD Regs or Buffer)
LDA ASCBUF,Y
ASL
ASL
ASL
ASL
STA TMP ;tenth's
INY
LDA ASCBUF,Y
AND #$0F
ORA TMP
STA TOD,X ;e.g. $DC08,X
RTS

parts of the code I can't follow because the info what is clock.low (and other vars) is missing.

BigDumbDinosaur

Also, at the beginning when he tests for AM/PM, he's doing:

lda $dc0b
and #128
cmp #00
bne pm


to see the condition of the AM/PM bit.

A simple:

lda hours             ;$DCOB
bmi is_pm


is all that is required, as the act of loading any value with bit 7 asserted sets the .N bit in the MPU status register.

Frankly, LokcalHorst,  I don't see how you're able to make heads or tails of his code.  It's peppered with all sorts of hard coded constants and address references (e.g., $DCOB for the hours register in the TOD) and is about as readable as the Dead Sea Scrolls.  :)  If one of my employees wrote machine code like that I'd suggest he seek employment elsewhere.
x86?  We ain't got no x86.  We don't need no stinking x86!

MIRKOSOFT

I tried both routines and all is working correctly but...


INPUT TIME is in 24-hour format
OUTPUT has to be 12am-pm
At the night it was not problem, am-pm bit was $00.


I turned on C128 around 14:00 (2:00pm) and what I see:
14:05a - so here's the Q: how it can work? CIA clock works in 12am-pm... it was ok if I look at the time, but comes 20th hour (8:00pm)...
and output was: 2::00a - it seems that it adds one to tenth - from $31 to $32 and $39 to $3a (simple 'cause 19:59 was 1 and 9 - so $30 and $39...)


But how it can happen? Input time is in 24hour format, but CIA it supports not... and the routines working correctly at AM.


I attached two screenshots with time. After 20:00 I began experiment with changing time to other, e.g. 12:59, after minute it was correct 01:00a, but I'm not sure how is correct format of am-pm time:
12:59am or 0:00am ? I think 12:59am
I will try more, but if can you help, thanks, many thanks
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

MIRKOSOFT

Hi!


So, I tried all.


I changed time, rewrite order of setting, first hours then minutes, first minutes then hours...
I created subtract from 24hr format to 12ampm format - tested separately - works correctly.
Next attached two screenshots:
1st: run at emulator with setting time 00:00 - you can see starts with 01:00a and continues


2nd: real machine - I set computer time to 5:55am and you can see that machine works only with minutes - 07:55p - hour was never changed...


So, I don't know where I do the same mistake, please help me anybody! 
Here's source code:

showtime:
lda tod+3 // load hour
and #128 // PM test
cmp #00
bne pm
lda #65 // set AM
jmp tost
pm: lda #80 // set PM
tost: sta clock.correctly+5
lda #58 // : - separator
sta clock.correctly+2
lda tod+2 // minutes
jsr bcd2asc
lda ascbuf
sta clock.correctly+3
lda ascbuf+1
sta clock.correctly+4
lda tod+3 // hours
and #$7f
jsr bcd2asc
lda ascbuf
sta clock.correctly
lda ascbuf+1
sta clock.correctly+1
lda tod // start the clock
jmp clock.possh // jump to print on screen


tis: jsr odpocitat // subtracting 24hr > 12ampm
lda clock.correctly+3 // minutes
sta ascbuf
lda clock.correctly+4
sta ascbuf+1
ldx #2
jsr asc2bcd
lda #58 // : - separator
sta clock.correctly+2
lda clock.correctly // hours
sta ascbuf
lda clock.correctly+1
sta ascbuf+1
ldx #3
jsr asc2bcd
lda tod,x // p = PM flag ORA
ora p
sta tod,x
lda #00
sta tod // start the clock
rts



bcd2asc: // input a = packed BCD, output ASCII (buffer)
pha
lsr
lsr
lsr
lsr
ora #$30
sta ascbuf // tenth's
pla
and #$0f
ora #$30
sta ascbuf+1 // one's
rts

asc2bcd: // input ASCII (Buffer), output BCD (TOD Regs or Buffer)
lda ascbuf
asl
asl
asl
asl
sta temporary // tenth's
lda ascbuf+1
and #$0f
ora temporary
sta tod,x // e.g. $DC08,X
rts



odpocitat: // subtractor of 24hr > 12ampm
lda clock.correctly
cmp #$30
bne more
lda clock.correctly+1
cmp #$30
bne koniec0
lda #$31
ldx #$32
sta clock.correctly
stx clock.correctly+1
jmp koniec0
more: cmp #$31
beq ten
cmp #$32
beq twenty
koniec0:
lda #00 // flag AM
sta p
rts
ten: lda clock.correctly+1
cmp #$33
bmi koniec0
sbc #$02
sta clock.correctly+1
lda #$30
sta clock.correctly
koniec1: // flag PM
lda #128
sta p
rts
twenty:
dec clock.correctly
lda clock.correctly+1
sbc #$03
sta clock.correctly+1
jmp koniec1



ascbuf:
.byte 0,0,0,0,0,0,0

temporary:
.byte 0

p:
.byte 0


Many many thanks.


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

MIRKOSOFT

 I tested it on other C128 and hour was set to 00, so how to set hour?
There is the main and only one problem...


Can you help me?


Thank you very much.


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

MIRKOSOFT

Hi!


Is possible when is written wrong value to hour-byte that it is ignored?
'cause hour-byte has this structure:
7.bit = AM/PM flag
6-5- unused
4.bit tenth of hours
3-1 - ones


So, can help this:
and #%10011111


Thanks for every every help, 'cause this is main problem and need to be solved.


Cheers,


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

LokalHorst

#7
Hi Miro,
don't know exactly what went wrong, but the hours need a special preprocessing.
You can use the following as a template. I assumed that the input time string has the following format HH:MM:SS, hours as 24h - 00=midnight
(the init was missing in your previous code - 50/60hz and alarm/time)

set_time
...
LDA $0A03 ;pal/ntsc flag - pal=$ff ntsc=$00
ASL ;set carry if pal
PHP
LDA CIA1CRA ;$dc0e
ASL
PLP
ROR ;set 50/60hz clock freq. for TOD (bit7)
STA CIA1CRA ;$dc0e

LDA CIA1CRB ;$dc0f
AND #$7F ;clear bit7 for setting time (alarm otherwise)
STA CIA1CRB ;$dc0f

;hours preprocessing
LDY #offs ;offset into the time string (ascii) to hours 24h format
JSR asc2bcd ;return bcd in A
CMP #$12 ;check for (high)noon (12:00 to 12:59 is stored as 12:xx AM)
BEQ set_as_is
AND #$FF ;check for midnight (00:00 to 00:59)
BNE check_am
LDA #$92 ;$80 + BCD 12 (00:xx is stored as 12:xx PM)
BMI set_as_is ;skip

check_am
CMP #$12 ;check for am/pm
BCC set_as_is ;skip if smaller than $12
oops - we need decimal mode for this to work from 20:xx to 23:xx
SED

SBC #$12 ;turn 13:xx to 23:xx into 01:xx to 11:xx
CLD
ORA #$80 ;PM flag

set_as_is
EDIT: removed indexed addressing to TOD regs. (doesn't make much sense here)
STA CIA1TOD +3 ;$dc08 + x -> $dc0b
;minutes
INY ;skip separator ':'
JSR asc2bcd
STA CIA1TOD +2 ;$dc0a
;seconds
INY ;skip separator ':'
JSR asc2bcd
STA CIA1TOD +1 ;$dc09
LDA #$00
STA CIA1TOD ;$dc08 start clock
RTS

;return BCD in A, ascbuf is the date/time string, y offset
asc2bcd
LDA ASCBUF,Y
INY
ASL
ASL
ASL
ASL
STA TMP ;tenth's
LDA ASCBUF,Y
INY
AND #$0F ;one's
ORA TMP
RTS

ASCBUF

MIRKOSOFT

Hi!


Last one problem:


When my computer switches correctly to 12:59a, I exited aceCommander128. After starting again shows 13:59p, then after minute 14:00p, but when was restarted it was shown correctly 01:01a.


Look at screenshot. It's really last problem with time, can you help me how to solve it?


Many many thanks!


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

LokalHorst

#9
Hi Miro,
the screenshot isn't helpful without your code, I guess the 'showtime' routine doesn't check for 12am/pm - 12:00a to 12:59a should be 00:00a to 00:59a (midnight).
I revised and tested my example routines and they work flawlessly (both set_time & read_time). If you want to keep your label naming replace 'outstr' with 'time.correctly' and don't change the indexed addressing which voids the purpose of 'asc2bcd' & 'bcd2asc' in reading/writing multiple numbers. Delete all the stuff at 'odpocitat:' it's not required.


set_time:
...
LDA $0A03 ;pal/ntsc flag - pal=$ff ntsc=$00
ASL ;set carry if pal
PHP
LDA CIA1CRA ;$dc0e
ASL
PLP
ROR ;set 50/60hz clock freq. for TOD (bit7)
STA CIA1CRA ;$dc0e

LDA CIA1CRB ;$dc0f
AND #$7F ;clear bit7 for setting time (alarm otherwise)
STA CIA1CRB ;$dc0f
SEI

;hours preprocessing
LDY #offs ;offset into the input string (ascii) to hours 24h format
JSR asc2bcd ;return bcd in A (00 to 23)
BNE check_am ;skip if not zero
;special case 00 midnight is set as 12PM
LDA #$92 ;$80 + BCD 12
BMI set_as_is

check_am:
CMP #$12 ;check for am/pm
BCC set_as_is ;skip if in range 01 - 11 bcd
BEQ set_as_is ;special case noon is set as 12AM
SED ;enable decimal mode (carry is set already)
SBC #$12 ;change 13 .. 23 to 01 .. 11
CLD
ORA #$80 ;PM flag

set_as_is:
STA CIA1TOD +3 ;$dc0b
;minutes
INY ;skip separator ':'
JSR asc2bcd
STA CIA1TOD +2 ;$dc0a
;seconds
INY
JSR asc2bcd
STA CIA1TOD +1 ;$dc09
LDA #$00
STA CIA1TOD ;$dc08 start clock
CLI
RTS

asc2bcd: ;return BCD in A, inbuff is the input string, y offset (increment by 2 on return)
LDA INBUFF,Y  ;tenth's
INY
ASL
ASL
ASL
ASL
STA hi_nib +1
LDA INBUFF,Y  ;one's
INY
AND #$0F
hi_nib:
ORA #$00 ;combine with hi-nibble
RTS

INBUFF: .byte 'time: 23:35:20 date: 21/07/2010' ;input example
OFFS = 6 ;point to first hour digit (in above example)


read_time:

LDY #$00 ;index 0 to outstr
LDA CIA1TOD +3 ;hours $dc0b
AND #$1F
CMP #$12
BNE no_change ;skip if not 12am or pm
BIT CIA1TOD +3
BMI no_change ;skip if pm
LDA #$00 ;12am change to 00am midnight

no_change:
JSR bcd2asc
INY  ;skip separator ':'
LDA CIA1TOD +2  ;minutes
JSR bcd2asc

;optional
;INY
;LDA CIA1TOD +1  ;seconds
;JSR bcd2asc

LDA #'a'
BIT CIA1TOD +3
BPL store_ampm
LDA #'p'
store_ampm:
STA outstr,Y
LDA CIA1TOD ;un-latch clock

;insert the following if you want to suppress
;the leading zero if hour is 00 to 09
LDA outstr ;1st char
CMP #$30
BNE skippy
LDA #' ' ;blank
STA outstr

skippy:
RTS

bcd2asc:
PHA
LSR
LSR
LSR
LSR
ORA #$30
STA outstr,Y
INY
PLA
AND #$0F
ORA #$30
STA outstr,Y
INY
RTS

outstr: .byte '00:00a' ;string template (or 00:00:00)


changes for 24h display:

read_time:
LDY #$00 ;index 0 to outstr
LDA CIA1TOD +3 ;hours $dc0b
AND #$1F
CMP #$12
BNE check_pm ;skip if not 12am or pm
LDA #$00 ;change 12am to 00am

check_pm:
BIT CIA1TOD +3
BPL no_change
CLC ;if pm set add bcd 12
SED
ADC #$12
CLD

no_change:
JSR bcd2asc
...
(remaining part as above, remove the am/pm thing @ the end)

MIRKOSOFT

I did it, I let only your code except displaying.
Works correctly, many many thanks.


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

LokalHorst

Addendum:

If the routine read_time (showtime in your code) is being part of the irq - there is no need to read out the time 50/60 times a second (especially not if only hours & minutes are displayed).
Insert the following at the beginning of read_time to have a fancy blinking colon (0.5 sec interval):

read_time:
LDA #$04
BIT CIA1TOD ;$dc08
BNE cont
LDA #' ' ;blank
STA outstr +2
RTS

cont:
LDA #':' ;colon
STA outstr +2
...
(as with previous post)