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 {
	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
		}
	}
}
