irqAddr = 0xDDDD
playstr = 0xd37a

clearBreakPoints()
for i = 0xD400, 0xD41F do
  setBreakPoint(2, i, 3)
end
setBreakPoint(4, 0x0000, 3)
setBreakPoint(4, irqAddr, 3)
setBreakPoint(4, playstr, 3)

playtime = "2:15"
intFreq = -1

f = io.open("/tmp/sid_data.bin", "wb")
playt = string.sub ("00:00", 1,(5-string.len(playtime))) .. playtime
if string.len(playt) ~= 5 then
  clearBreakPoints()
  return false
end
acttime = 0
playtime = 1000000

gatetrig = { 0x00, 0x00, 0x00 }
save = false                    --[==[ start save if SID register written]==]
frameCnt = 0
outBuf = {}
for i = 0, 0x3FFF do
  outBuf[i] = 0x00
end

function writeBlock(isLast)
  if intFreq < 0 then
    local lptAddr = OR(readWordRaw(0x3FFFF4), 0x3FC000)
    local lineAddr = OR(readWordRaw(lptAddr + 0x54), 0x3FC000)
    intFreq = (AND(readMemoryRaw(lineAddr), 0x0F) * 100)
              + (AND(readMemoryRaw(lineAddr + 1), 0x0F) * 10)
              + AND(readMemoryRaw(lineAddr + 2), 0x0F)
    mprint("intFreq = ", intFreq)
    playtime = (tonumber(string.sub(playt, 1, 2)) * 60
                + tonumber(string.sub(playt, 4, 5))) * intFreq
    outBuf[0x3FFD] = AND(intFreq + 206, 0xFF)
  end
  if isLast then
    if frameCnt < math.floor(intFreq * 0.5 + 0.5) then
      frameCnt = math.floor(intFreq * 0.5 + 0.5)
    end
    outBuf[0x3FFE] = AND(frameCnt, 0xFF)
    outBuf[0x3FFF] = SHR(frameCnt, 8)
  end
  for i = 0, 0x3FFF do
    f:write(string.char(outBuf[i]))
    outBuf[i] = 0x00
  end
  f:flush()
  frameCnt = 0
end

function writeFrame()
  if frameCnt >= 655 then
    writeBlock(false)
  end
  for i = 0, 24 do
    outBuf[i * 655 + frameCnt] = readMemory(0xD400 + i)
  end
  for i = 1, 3 do
    local p = ((i * 7) - 4) * 655 + frameCnt
    if AND(outBuf[p + 655], 0x01) == 0 then
      gatetrig[i] = 0x00
    elseif frameCnt > 0 then
      if AND(outBuf[p + 655 - 1], 0x01) == 0 then
        gatetrig[i] = 0x00
      end
    end
    outBuf[p] = OR(AND(outBuf[p], 0x0f), gatetrig[i])
    gatetrig[i] = 0x00
  end
  frameCnt = frameCnt + 1
  acttime  = acttime  + 1
end

function breakPointCallback(t, a, v)
  if not save then
    if (t == 0 or t == 3) then
      if a == 0x0000 then
        clearBreakPoints()
        return true
      elseif a == playstr then
        if readIOPort(0xB3) >= 0x44 then
          save = true
          acttime = 0
        end
        return false
      elseif a == irqAddr then
        return false
      end
    elseif t == 2 and (a >= 0xD400 and a <= 0xD41F) then
      return false
    end
  end
  if save then
    if (t == 0 or t == 3) then
      if a == irqAddr then
        if getIM() == 2 and AND(readIOPort(0xB4), 0x22) ~= 0 then
          if acttime < playtime then
            writeFrame()
            return false
          elseif frameCnt > 0 then
            writeBlock(true)
            f:close()
            clearBreakPoints()
            mprint ("save time elapsed")
            return true
          end
        end
      elseif a == playstr then
        return false
      elseif a == 0x0000 then
        if frameCnt > 0 then
          writeBlock(true)
        end
        f:close()
        clearBreakPoints()
        return true
      end
    elseif t == 2 then
      if a >= 0xD400 and a <= 0xD41F then
        local sidReg = AND(a, 0x1F)
        if sidReg == 0x04 or sidReg == 0x0B or sidReg == 0x12 then
          if AND(v, 0x01) > AND(readMemory(a), 0x01) then
            gatetrig[(sidReg + 3) / 7] = 0x80
          end
        end
        return false
      end
    end
  end
  return true
end
