mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
160 lines
3.0 KiB
Go
160 lines
3.0 KiB
Go
package pit
|
||
|
||
/*
|
||
Programmable Interval Timer
|
||
i8053, MSM82C53, КР580ВИ53
|
||
|
||
By Romych, 2025.03.04
|
||
*/
|
||
|
||
// Timer work modes
|
||
const (
|
||
TimerModeIntOnFin = iota
|
||
TimerModeOneShot
|
||
TimerModeRateGen
|
||
TimerModeSqWave
|
||
)
|
||
|
||
// Timer load counter modes
|
||
const (
|
||
TimerRLMsbLsb = iota
|
||
TimerRLLsb
|
||
TimerRLMsb
|
||
TimerRLLsbMsb
|
||
)
|
||
|
||
type Timer8253Ch struct {
|
||
rl byte // load mode
|
||
mode byte // counter mode
|
||
bcd bool // decimal/BCD load mode
|
||
load uint16 // value to count from
|
||
counter uint16 // timer counter
|
||
fb bool // first byte load flag
|
||
started bool // true if timer started
|
||
fired bool
|
||
}
|
||
type I8253 struct {
|
||
//chNo byte
|
||
channel [3]Timer8253Ch
|
||
}
|
||
|
||
type I8253Interface interface {
|
||
//Init()
|
||
Configure(value byte)
|
||
Load(chNo int, value byte)
|
||
Counter(chNo int) uint16
|
||
Fired(chNo int) bool
|
||
Start(chNo int) bool
|
||
}
|
||
|
||
func New() *I8253 {
|
||
return &I8253{
|
||
//chNo: 0,
|
||
channel: [3]Timer8253Ch{
|
||
{0, 0, false, 0, 0, true, false, false},
|
||
{0, 0, false, 0, 0, true, false, false},
|
||
{0, 0, false, 0, 0, true, false, false},
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *I8253) Tick(chNo int) {
|
||
tmr := &t.channel[chNo]
|
||
if tmr.started {
|
||
tmr.counter--
|
||
if tmr.counter == 0 {
|
||
switch tmr.mode {
|
||
case TimerModeIntOnFin:
|
||
{
|
||
tmr.started = false
|
||
tmr.fired = true
|
||
}
|
||
case TimerModeOneShot:
|
||
tmr.started = false
|
||
case TimerModeRateGen:
|
||
tmr.started = false
|
||
case TimerModeSqWave:
|
||
{
|
||
tmr.started = true
|
||
tmr.counter = tmr.load
|
||
tmr.fired = true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func (t *I8253) Counter(chNo int) uint16 {
|
||
return t.channel[chNo].counter
|
||
}
|
||
|
||
func (t *I8253) Fired(chNo int) bool {
|
||
f := t.channel[chNo].fired
|
||
if f {
|
||
t.channel[chNo].fired = false
|
||
}
|
||
return f
|
||
}
|
||
|
||
func (t *I8253) Start(chNo int) bool {
|
||
return t.channel[chNo].started
|
||
}
|
||
|
||
/*
|
||
Timer config byte: [sc1:0][rl1:0][m2:0][bcd]
|
||
sc1:0 - timer No
|
||
rl=01-LSB, 10-MSB, 11-LSB+MSB
|
||
mode 000 - intRq on fin,
|
||
001 - one shot,
|
||
x10 - rate gen,
|
||
x11 - sq wave
|
||
*/
|
||
|
||
func (t *I8253) Configure(value byte) {
|
||
chNo := (value & 0xC0) >> 6
|
||
rl := value & 0x30 >> 4
|
||
t.channel[chNo].started = false
|
||
t.channel[chNo].rl = rl
|
||
t.channel[chNo].mode = (value & 0x0E) >> 1
|
||
t.channel[chNo].fb = true
|
||
t.channel[chNo].bcd = value&0x01 == 1
|
||
t.channel[chNo].load = 0
|
||
}
|
||
|
||
func (t *I8253) Load(chNo byte, value byte) {
|
||
timer := &t.channel[chNo]
|
||
switch timer.rl {
|
||
case TimerRLMsbLsb:
|
||
// MSB+LSB
|
||
if timer.fb {
|
||
// MSB
|
||
timer.load = uint16(value) << 8
|
||
timer.fb = false
|
||
} else {
|
||
// LSB
|
||
timer.load |= uint16(value)
|
||
timer.started = true
|
||
}
|
||
case TimerRLLsb:
|
||
// LSB Only
|
||
timer.load = (timer.load & 0xff00) | uint16(value)
|
||
timer.started = true
|
||
case TimerRLMsb:
|
||
// MSB Only
|
||
timer.load = (timer.load & 0x00ff) | (uint16(value) << 8)
|
||
timer.started = true
|
||
case TimerRLLsbMsb:
|
||
// LSB+MSB
|
||
if timer.fb {
|
||
// LSB
|
||
timer.load = uint16(value)
|
||
timer.fb = false
|
||
} else {
|
||
// MSB
|
||
timer.load = (uint16(value) << 8) | (timer.load & 0x00ff)
|
||
timer.started = true
|
||
timer.counter = timer.load
|
||
}
|
||
}
|
||
}
|