16 June 2015, 15:55 | #21 |
Registered User
Join Date: Oct 2009
Location: Germany
Posts: 3,304
|
Yes, that is what I meant. Kill the system means kill it (incl. clock) but then you don`t go back to it. On the other hand there is start from WB and "take over the system" with later restoration. So you can work on WB which is as stable as before you took over the system.
|
16 June 2015, 17:24 | #22 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
You're right. Sorry. I exchanged load and save.
|
17 June 2015, 04:55 | #23 |
old bearded fool
Join Date: Jan 2010
Location: Bangkok
Age: 56
Posts: 779
|
phx,
Thanks for verifying that, because it made me doubt my own understanding of the system. Initially I thought that 'move.w #$b,$1c(a0)' was some kind of patch for the unix time data, but then after rechecking the offset it was not patching a word in that region, you cleared that up nicely, but I still don't fully understand how DoIO() works. EDIT: Anyone who knows, Is there some way to preserve tab formatting in the vBulletin editor (advanced mode) when editing a post? It's driving me nuts, have to remove and insert a fresh paste of the whole source between the code tags every time before saving. Last edited by modrobert; 17 June 2015 at 08:11. |
17 June 2015, 16:05 | #24 |
old bearded fool
Join Date: Jan 2010
Location: Bangkok
Age: 56
Posts: 779
|
After some brief testing, my routine seems to work OK. Here is the relevant code I've added to startup.i.
Code:
move.l $4.w,a6 move.l a6,a5 ; execbase in a5 lea battresname(pc),a1 ; battclock.resource jsr -498(a6) ; OpenResource() movea.l d0,a4 ; battclockbase in a4 move.l a4,d0 ; hmm... bne.b .battok bra .fail .battok moveq #$28,d0 ; want 40 bytes allocated move.l #$10001,d1 ; MEMF_ANY, MEMF_CLEAR? jsr -198(a6) ; AllocMem() move.l d0,a3 ; allocated mem in a3 tst.l d0 beq .fail move.l d0,a1 lea timerdevname(pc),a0 moveq #0,d0 move.l d0,d1 jsr -444(a6) ; OpenDevice() move.l d0,d6 ext.w d6 ; byte to word ext.l d6 ; word to long, d6 equals 0? bne.b .fail moveq #0,d0 move.b d0,8(a3) ; start building IORequest move.b d0,9(a3) suba.l a1,a1 move.l a1,$a(a3) move.l a1,$e(a3) clr.l $24(a3) movea.l a4,a6 ; battclockbase in a4 jsr -12(a6) ; ReadBattClock() move.l d0,$20(a3) ; unix time in d0 move.w #$b,$1c(a3) ; io_Command = TR_SETSYSTIME movea.l a3,a1 movea.l a5,a6 ; execbase in a5 jsr -456(a6) ; DoIO() movea.l a3,a1 jsr -450(a6) ; CloseDevice() movea.l a3,a1 moveq #$28,d0 ; free the 40 bytes jsr -210(a6) ; FreeMem() .fail ; snip rts battresname dc.b 'battclock.resource',0 timerdevname dc.b 'timer.device',0 NOTE: The source code is converted to compile with Devpac (had to add some directives, change a few instructions, etc.). |
18 June 2015, 11:15 | #25 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
Very good. There is just one disadvantage: you need an RTC and at least OS2.0(?) for battclock.resource.
Maybe it also works without RTC, by remembering the system time and resetting the TOD to zero at the beginning of your program. At the end you will set the system time to the saved timeval + the new TOD count. As long as your code doesn't mess with the TOD, and as long as the OS and the interrupts are disabled, I see no reason why that shouldn't work. At the start of your program, get SysTime and reset TOD: Code:
; a6 = TimerDevice lea timval,a0 jsr -66(a6) ; GetSysTime ; disable interrupts, take over system ; ... ; reset TOD lea $bfe001,a0 ; CIA-A moveq #0,d0 move.b d0,$a00(a0) ; TODHI move.b d0,$900(a0) ; TODMID move.b d0,$800(a0) ; TODLO Code:
lea $bfe001,a0 moveq #0,d0 move.b $a00(a0),d0 ; TODHI lsl.w #8,d0 move.b $900(a0),d0 ; TODMID lsl.l #8,d0 move.b $800(a0),d0 ; TODLO ; restore system, enable interrupts ; ... ; a6 = TimerDevice ; d0 = TOD count since start lea timeval,a0 add.l TV_MICRO(a0),d0 divu TD_TODHERTZ(a6),d0 move.l d0,d1 ext.l d0 add.l d0,TV_SECS(a0) swap d1 ext.l d1 move.l d1,TV_MICRO(a0) ; set system time, pass timeval to TR_SETSYSTIME ; ... |
18 June 2015, 12:24 | #26 |
old bearded fool
Join Date: Jan 2010
Location: Bangkok
Age: 56
Posts: 779
|
Isn't the TOD frozen when you disable all interrupts (#$7FFF / %0111111111111111)?
I thought that was the reason "time stand still" when running intro. EDIT: Think I get it now, after staring at your code a bit more. I confused TOD with the system time due to the abbreviation "Time Of Day", but it's actually counting HSYNC events. The interrupt handler updating the system time by dividing ticks is disabled while TOD keeps running, right? Can you explain the TV_MICRO part of the code? Last edited by modrobert; 18 June 2015 at 20:39. |
18 June 2015, 21:18 | #27 | |||
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
Quote:
Quote:
I didn't test this code myself. It was just an idea I had when reading your solution. Quote:
After the ticks have been added you can use this timeval to set your new system time (DoIO, TR_SETSYSTIME). |
|||
19 June 2015, 09:55 | #28 |
old bearded fool
Join Date: Jan 2010
Location: Bangkok
Age: 56
Posts: 779
|
I was too lazy to implement all of your code, and wasn't sure how exactly, so what I did was testing your theory using a breakpoint in the MonAm debugger (love that thing).
Added this code right before entering the intro. Code:
lea $bfe001,a0 ; CIA-A moveq #0,d0 move.b d0,$a00(a0) ; TODHI move.b d0,$900(a0) ; TODMID move.b d0,$800(a0) ; TODLO Code:
lea $bfe001,a0 moveq #0,d0 move.b $a00(a0),d0 ; TODHI lsl.w #8,d0 move.b $900(a0),d0 ; TODMID lsl.l #8,d0 move.b $800(a0),d0 ; TODLO So, assuming 50Hz for my PAL system. 592/50 = 11.84 seconds Looks like a winner, the error margin most likely my stop watch reaction time, hehe. Last edited by modrobert; 19 June 2015 at 10:00. |
31 July 2015, 16:55 | #29 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,604
|
Don't know if I'm too late, seems you already got a few replies.
The hardware has a TOD clock since the first A1000, which means you're up the wrong track if you try to use any lib function that isn't present in 1.2. Another clue is that a battery has nothing at all to do with a TOD clock chip. BattClock is a strange name for a lib. TOD clock doesn't stop just because you turn off the interrupts... that would make it pretty useless It's a simple hardware counter. So why is the Workbench clock incorrect? Because WB function to show time just increments the values it read once. Maybe it will read them again if you wait a minute. Maybe something unrelated triggers a re-read. Either way you have to trigger the re-read of the clock chip. timer.device GetSysTime followed by SetSysTime looks like it should update the local system TOD values, but it could be that you also have to find out how to trigger the WB to update its on-screen time value, in a WB 1.2+ compatible way if you want to support all Amigas. It could be that GetSysTime() gives you the incorrect WB values again. I use this for the clock display in AsmTwo, which seems to work. Code:
TODtick: ;->d0.l, 1 tick=1/50 sec bsr.s TOD move.w TODData+6(PC),d0 mulu #3000,d0 ;<<10-(<<4+<<3) *3 (add) add.l TODData+8(PC),d0 RTS TOD: MOVEM.L D1-A6,-(SP) ;sys clock minutes since 00:00 -> d0. move.l DOSBASE(A4),A6 lea TODData(PC),a2 ;pokes 3 longs move.l a2,d1 jsr -192(a6) ;DateStamp move.l 4(a2),d0 ;div by 60 to get mm.hh.L MOVEM.L (SP)+,D1-A6 RTS TODData:blk.l 3,0 Last edited by Photon; 31 July 2015 at 17:03. |
31 July 2015, 17:28 | #30 | |
Moderator
Join Date: Nov 2001
Location: Germany
Posts: 866
|
Quote:
it uses (you have to open timer.device before): Code:
_SetClockLoad move.l a6,-(a7) move.l (gl_execbase,GL),a6 jsr (_LVOForbid,a6) lea (_battclock),a1 jsr (_LVOOpenResource,a6) tst.l d0 beq .fail move.l d0,a6 jsr (_LVOReadBattClock,a6) move.l (gl_execbase,GL),a6 tst.l d0 beq .fail move.l (gl_timerio,GL),a1 move.l d0,(IOTV_TIME+TV_SECS,a1) clr.l (IOTV_TIME+TV_MICRO,a1) move.w #TR_SETSYSTIME,(IO_COMMAND,a1) jsr (_LVODoIO,a6) .fail jsr (_LVOPermit,a6) move.l (a7)+,a6 rts |
|
31 July 2015, 19:28 | #31 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,604
|
Yes, you would have come across this before Your way should update the clock in WB. But... WHDLoad has set 2.0 as minimum kickstart version to support. In this case I think it can be done with the same functions in just timer.device?
Anyway, the TOD clock circuit keeps on ticking and giving correct time if you read it, for as long as the machine is on, on any Amiga ever made. If you have an expansion with battery, the expansion clock chip keeps time also when power is off. Last edited by Photon; 31 July 2015 at 19:42. |
31 July 2015, 20:06 | #32 |
Moderator
Join Date: Nov 2001
Location: Germany
Posts: 866
|
I would think it is feasible to restore the clock only on OS 2+.
I doubt that somebody cares about the clock on Kick 1.2/3 (are there really people using 1.3 besides to put a floppy in the drive?). |
01 August 2015, 21:25 | #33 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,604
|
Well, why create a completely unnecessary dependency just to read and set the TOD clock? It only takes one to affect the whole program, and if it's put in a startup source without thinking it affects all programs using it.
|
04 August 2015, 01:43 | #34 |
old bearded fool
Join Date: Jan 2010
Location: Bangkok
Age: 56
Posts: 779
|
Photon and Wepl,
Thanks for the suggestions. BTW: In case you missed it, there were already three solutions prior to your suggestions in the thread. 1) Mask the specific interrupt bit to allow timers (works on any version, but Toni objected, not safe). [by phx] Code:
move.w #$7FF7,d0 ; %0111111111110111 (#$8 bit not set) 3) Clearing TOD counter before intro, and then correcting system time after intro based on TOD counter on exit (works on any version, provided the intro leaves TOD counters alone). [by phx] As an added bonus I disassembled the 'setclock' binary from WB 3.1 with comments (and it compiles bit perfect compared to original with 'vasm'). Last edited by modrobert; 05 August 2015 at 00:27. |
04 August 2015, 19:11 | #35 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,604
|
Yeah, I noticed, just added another way that I thought was right. I.e. Read and set TOD clock with timer.device in the universal way, if possible. Both after turning ints on again. (I think you misinterpreted 3) )
I found an old source that says it's a command "ClockLoad" disassembled. Bit crap but if it helps. It just seems a basic function and it's all about which functions nudge WB's own functions to update it. |
04 October 2015, 20:10 | #36 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 260
|
clock problem
Hi,
I’m the coder of Copper-rulez-AGAin.lha (Aminet). daxb you are right. A demo that returns to the workbench shouldn’t affect the RTC. Well, I didn’t care about this fact and I was caught . To all members of this discussion: It was a pleasure to read because of its high quality stuff. I’ve learned a lot. Good work modrobert . Your sourcecode helped me to understand how to use the battery clock resource and the timer device. BTW, I’ve optimized and expanded your code a little bit: Code:
move.l $4.w,a6 move.l a6,a5 ; execbase in a5 lea battresname(pc),a1 ; battclock.resource jsr -498(a6) ; OpenResource() movea.l d0,a4 ; battclockbase in a4 move.l a4,d0 ; hmm... beq.b .fail .battok moveq #$28,d0 ; want 40 bytes allocated (size of ; timer-request-structure) move.l #$10001,d1 ; MEMF_ANY, MEMF_CLEAR? jsr -198(a6) ; AllocMem() move.l d0,a3 ; allocated mem in a3 tst.l d0 beq .fail move.l d0,a1 lea timerdevname(pc),a0 moveq #0,d0 ; Unit 0 = UNIT_MICROHZ moveq #0,d1 ; No flags jsr -444(a6) ; OpenDevice() tst.l d0 ; equal 0 ? bne.b .fail moveq #0,d0 ; start building IORequest / ; TimerRequest structure move.b d0,8(a3) ; LN_Type = NULL move.b d0,9(a3) ; LN_Pri = NULL move.l d0,$a(a3) ; LN_Name = No pointer move.l d0,$e(a3) ; MN_ReplyPort = No pointer movea.l a4,a6 ; battclockbase in a4 move.l d0,$24(a3) ; TV_micro =0 microseconds jsr -12(a6) ; ReadBattClock() movea.l a3,a1 move.l d0,$20(a3) ; TV_secs = unix time in seconds beq.b .no_sys_time_refresh ; Equal 0 (Invalid value) ? movea.l a5,a6 ; execbase in a5 move.w #$b,$1c(a3) ; IO_Command = TR_SETSYSTIME jsr -456(a6) ; DoIO() .no_sys_time_refresh movea.l a3,a1 jsr -450(a6) ; CloseDevice() movea.l a3,a1 moveq #$28,d0 ; free the 40 bytes jmp -210(a6) ; FreeMem() .fail rts battresname dc.b 'battclock.resource',0 timerdevname dc.b 'timer.device',0 But the battery clock resource has a bug. Working with OS 3.0 on a real A1200 without a RTC the return value of OpenResource() is always nonzero. Apart from this behaviour OpenResource() returns a zero when working on a MiST. Thats's were my fixed demo aborted with the error message "Can't find battery backed up clock". The behaviour of this function call seems to be different on original hardware and on a MiST which doesn't have a RTC. So it's better to use PHX's solution for refreshing the system time. PHX, I've also checked your startup code using the TOD and expanded it. Good idea to use the TOD directly in addition to the system . The TOD must not be set to zero and messed up this way. You can also get the difference from TOD before and after the demo/intro. But a TOD overflow must be checked. Because TOD runs independently from any interrupts they can be all turned off. Code:
move.l $4.w,a6 ;Execbase lea timer_request_struc(pc),a1 ;Timer-request-structure moveq #0,d0 ;Unit 0 (UNIT_MICROHZ) & Null for entrys in struc move.b d0,8(a1) ;LN_Type: Entry type = Null move.b d0,9(a1) ;LN_Pri: Priority of the structure = Null moveq #0,d1 ;No Flags for device move.l d0,$a(a1) ;LN_Name: No name for the structure lea timer_device_name(pc),a0 ;Pointer to name of Timer-Device move.l d0,$e(a1) ;MN_ReplyPort: No Reply-Port jsr -444(a6) ;OpenDevice() tst.l d0 bne.s open_timer_device_error lea timer_request_struc(pc),a1 move.w #$a,$1c(a1) ;IO_Command = TR_GETSYSTIME jsr -456(a6) ;DoIO() jsr -120(a6) ;Disable() ;Take over the machine... move.l #$bfe001,a4 ;CIA-A base adress moveq #0,d0 move.b $a00(a4),d0 ;TOD-clock bits 23-16 swap d0 ;Shift bits to the right position move.b $900(a4),d0 ;TOD-clock bits 15-8 lsl.w #8,d0 ;Shift bits to the right position move.b $800(a4),d0 ;TOD-clock bits 7-0 move.l d0,TOD_time_save ;Save time before demo/intro starts movem.l d0-d7/a0-a6,-(a7) bsr demo ;start demo/intro movem.l (a7)+,d0-d7/a0-a6 move.l TOD_time_save(pc),d0 ;Time before starting demo/intro moveq #0,d1 move.b $a00(a4),d1 ;TOD-clock Bits 23-16 swap d1 move.b $900(a4),d1 ;TOD-clock Bits 15-8 lsl.w #8,d1 move.b $800(a4),d1 ;TOD-clock Bits 7-0 cmp.l d0,d1 ;TOD overflow? bge.s no_TOD_overflow ;No -> skip move.l #$ffffff,d2 ;Max TOD value sub.l d0,d2 ;Difference until overflow add.l d2,d1 ;+ value after overflow bra.s TOD_okay CNOP 0,4 ;Longword alignment for 68020+ no_TOD_overflow sub.l d0,d1 ;Get normal difference without overflow TOD_okay move.l d1,TOD_time_save ;Save period of demo/intro ;Restore system... move.l $4.w,a6 ;Execbase jsr -126(a6) ;Enable() move.l TOD_time_save(pc),d0 ;Period of demo/intro moveq #0,d1 move.b 212(a6),d1 ;Get VBlankFrequency lea timer_request_struc(pc),a1 divu.w d1,d0 ;Calculate seconds move.w #$b,$1c(a1) ;IO_command = TR_SETSYSTIME move.l d0,d1 ;Save seconds in d1 ext.l d0 ;Word to longword add.l d0,$20(a1) ;TV_SECS: Set Unix-Time seconds swap d1 ;Remainder of division mulu.w #10000,d1 ;*10000 = µs add.l d1,$24(a1) ;TV_MICRO: Set Unix-Time microseconds jmp -456(a6) ;DoIO() CNOP 0,4 open_timer_device_error rts CNOP 0,4 TOD_time_save DC.L 0 timer_request_struc DS.B 40 timer_device_name DC.B "timer.device",0 EVEN Quote:
Code:
/** Konvertiert gegliederte UTC-Angaben in Unix-Zeit. * Parameter und ihre Werte-Bereiche: * - jahr [1970..2038] * - monat [1..12] * - tag [1..31] * - stunde [0..23] * - minute [0..59] * - sekunde [0..59] */ long unixzeit(int jahr, int monat, int tag, int stunde, int minute, int sekunde) { const short tage_seit_jahresanfang[12] = /* Tage seit Jahresanfang ohne Tage des aktuellen Monats und ohne Schalttag */ {0,31,59,90,120,151,181,212,243,273,304,334}; int schaltjahre = ((jahr-1)-1968)/4 - ((jahr-1)-1900)/100 + ((jahr-1)-1600)/400; long tage_seit_1970 = (jahr-1970)*365 + schaltjahre + tage_seit_jahresanfang[monat-1] + tag-1; if ( (monat>2) && (jahr%4==0 && (jahr%100!=0 || jahr%400==0)) ) tage_seit_1970 += 1; /* +Schalttag, wenn jahr Schaltjahr ist */ return sekunde + 60 * ( minute + 60 * (stunde + 24*tage_seit_1970) ); } After analysing SetClock1.2 & 1.3 and ReadBattClock() in ROM I wrote this RTC-handler. It checks if a RTC is available, reads the RTC, converts the date/time to amiga UNIX time and sets the system time. As a bonus I've included an alternative subroutine to seek&reset the RTC. More information about the OKI RTC can be found here: http://www.amigawiki.de/lib/exe/fetch.php?media=dearts:m6242b_oki_datasheet.pdf |
|
05 October 2015, 14:39 | #37 | ||
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
Quote:
Quote:
|
||
05 October 2015, 20:50 | #38 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 260
|
Quote:
So my RTC-handler would fail there. I didtn't think OKI and RICOH are so incompatible to each other. Thanks for this hint. Anyway the A3000 had OS2.0 and the A4000 OS 3.0 with the battery clock resource. So we can control the RTC by the OS. |
|
06 October 2015, 16:31 | #39 | |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
|
It has small bug, leaks memory if OpenDevice() fails and I guess D0=0 return code probably would be good idea too.
Quote:
I guess it can only happen with real 68020 CPU (or 100% cycle sequence accurate clone) because returned data from floating bus depends on what CPU fetched previously. |
|
07 October 2015, 18:42 | #40 | ||
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 260
|
Quote:
Quote:
Code:
move.l #$dc0000,a0 ;RTC base address moveq #1,d0 ;Set HOLD-Bit in Control D-register move.b d0,$37(a0) ;to prevent register-carry during ;reading by freezing counter pulse nop ;Prevent parallel execution on the 68060 move.b $37(a0),d1 ;Check if Control D-register exists and.b #$f,d1 ;Mask out unimportant bits cmp.b d1,d0 ;Read = Write? bne.s no_RTC_found Code:
moveq #1,d0 ;Reset RTC-Counter move.b d0,$3f(a0) ;Set RSET-Bit in Control F-register nop ;Prevent parallel execution on the 68060 move.b $3f(a0),d1 ;1st check: Read to check whether ;Control F register exists moveq #$f,d2 and.b d2,d1 ;Only Bits 0-3 cmp.b d1,d0 bne.s reg_check_failed ;Read <> Write -> skip moveq #5,d0 ;Reset RTC-Counter, set 24 hours move.b d0,$3f(a0) nop ;Prevent parallel execution on the 68060 move.b $3f(a0),d1 ;2nd Control F register check and.b d2,d1 ;Only Bits 0-3 cmp.b d1,d0 bne.s reg_check_failed ;Read <> Write -> skip moveq #4,d0 ;Set 24 hours move.b d0,$3f(a0) nop ;Prevent parallel execution on the 68060 move.b $3f(a0),d1 ;3rd Control F register check and.b d2,d1 ;Only Bits 0-3 cmp.b d1,d0 bne.s reg_check_failed ;Read <> Write -> skip |
||
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
startup/system takeover | sidewinder | Coders. General | 15 | 28 February 2016 16:33 |
time clock prob a2000 | source | Hardware mods | 11 | 07 August 2011 13:16 |
A1200 Real Time Clock | Eclipse | support.Hardware | 4 | 22 March 2011 02:18 |
App to update Amiga System time from web time?? | DDNI | request.Apps | 2 | 31 December 2007 07:21 |
Reading the Real Time Clock | girv | Coders. General | 5 | 04 September 2007 18:30 |
|
|