izapple2/component/microPD1990ac.go

121 lines
2.5 KiB
Go

package component
import (
"time"
)
/*
microPD1990ac Serial I/O Calendar Clock IC
See:
https://www.semiee.com/file/backup/NEC-D1990.pdf
Used by the ThunderClock+ real time clock card.
The 40 bit register has 5 bytes (10 nibbles):
byte 4:
month, binary from 1 to 12
day of week, BCD 0 to 6
byte 3: day of month, BCD 1 to 31
byte 2: hour, BCD 0 to 23
byte 1: minute, BCD 0 to 59
byte 0: seconds, BCD 0 to 59
*/
type MicroPD1990ac struct {
clock bool // CLK state
strobe bool // STB state
command uint8 // C0, C1, C2 command. From 0 to 7
register uint64 // 40 bit shift register
}
const (
mpd1990commandRegHold = 0
mpd1990commandRegShift = 1
mpd1990commandTimeSet = 2
mpd1990commandTimeRead = 3
)
func (m *MicroPD1990ac) In(clock bool, strobe bool, command uint8, dataIn bool) {
// Detect signal raise
clockRaise := clock && !m.clock
strobeRaise := strobe && !m.strobe
// Update signal status
m.clock = clock
m.strobe = strobe
// On strobe raise, update command and execute if needed
if strobeRaise {
m.command = command
switch m.command {
case mpd1990commandRegShift:
// Nothing to do
case mpd1990commandTimeRead:
m.loadTime()
default:
// Ignore unknown commands (like set time)
//panic(fmt.Sprintf("PD1990ac command %v not implemented.", m.command))
}
}
// On clock raise, with shift enable, shift the register
if clockRaise && m.command == mpd1990commandRegShift {
// Rotate right the 40 bits of the shift register
lsb := m.register & 1
m.register >>= 1
m.register += lsb << 39
}
}
func (m *MicroPD1990ac) Out() bool {
/*
if m.command == mpd1990commandRegHold {
panic("Output on RegHold should be a 1Hz signal. Not implemented.")
}
if m.command == mpd1990commandTimeRead {
panic("Output on RegHold should be a 512Hz signal with LSB. Not implemented.")
}
*/
// Return the LSB of the register shift
return (m.register & 1) == 1
}
func (m *MicroPD1990ac) loadTime() {
now := time.Now()
var register uint64
register = uint64(now.Month())
register <<= 4
register += uint64(now.Weekday())
day := uint64(now.Day())
register <<= 4
register += day / 10
register <<= 4
register += day % 10
hour := uint64(now.Hour())
register <<= 4
register += hour / 10
register <<= 4
register += hour % 10
minute := uint64(now.Minute())
register <<= 4
register += minute / 10
register <<= 4
register += minute % 10
second := uint64(now.Second())
register <<= 4
register += second / 10
register <<= 4
register += second % 10
m.register = register
}