123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- -- Copyright © 2019 Pedro Gimeno Fortea
- -- This program may be used by anyone and may be freely copied and distributed
- -- in verbatim form. Modifications for personal use are allowed.
- -- NO IMPLIED WARRANTIES.
- -- TODO: Decide a proper license, as the one above sucks.
- -- Usage: luajit mode1to2.lua infile outfile
- -- Reconstruct MODE2/2352 from a MODE1/2048 image.
- -- The reconstruction does not include Reed-Solomon ECC.
- -- It only includes the 32-bit CRC EDC.
- -- This suffices for Mednafen's PSX module to accept the image as valid.
- -- According to the spec, the poly is:
- -- (x^16 + x^15 + x^2 + 1) * (x^16 + x^2 + x + 1)
- -- which equals x^32 + x^31 + x^16 + x^15 + x^4 + x^3 + x + 1
- -- but the x^31 term is in bit 0 of the byte
- -- therefore the polynomial word is (in bit reverse order):
- -- 11011000000000011000000000000001
- -- which in hex is: 0xD8018001
- local ffi = require('ffi')
- local bit = require('bit')
- local bxor = bit.bxor
- local band = bit.band
- local blshift = bit.lshift
- local brshift = bit.rshift
- local CRCpoly = 0xD8018001
- local CRCtable
- local function makeCRCTable()
- -- Make a bit-reversal table
- local B = ffi.new('unsigned char[256]')
- for i = 0, 255 do
- B[i] = band(blshift(i, 7), 0x80)
- + band(blshift(i, 5), 0x40)
- + band(blshift(i, 3), 0x20)
- + band(blshift(i, 1), 0x10)
- + band(brshift(i, 1), 0x08)
- + band(brshift(i, 3), 0x04)
- + band(brshift(i, 5), 0x02)
- + band(brshift(i, 7), 0x01)
- end
- CRCtable = ffi.new('uint32_t[256]')
- for i = 0, 255 do
- local ShiftReg = B[i]
- for j = 0, 7 do
- ShiftReg = bxor(brshift(ShiftReg, 1),
- band(CRCpoly, -band(ShiftReg, 1)))
- CRCtable[B[i]] = band(ShiftReg, 0xFFFFFFFF)
- end
- end
- end
- local function CRC(data)
- local crc = 0
- for i = 16, 2071 do
- crc = bxor(brshift(crc, 8), CRCtable[band(bxor(crc, data[i]), 0xFF)])
- end
- return crc
- end
- local function main()
- makeCRCTable()
- local buf = ffi.new('unsigned char[2352]')
- ffi.fill(buf, 2352)
- local f = io.open(arg[1], "rb")
- local size = f:seek("end")
- if size % 2048 ~= 0 then
- f:close()
- error("File length is not a multiple of 2048.")
- end
- f:seek("set")
- local data = ffi.new('unsigned char[?]', size)
- print("reading image")
- for i = 0, size - 1, 2048 do
- ffi.copy(data + i, f:read(2048))
- if i % 16777216 == 0 then
- collectgarbage() -- needs a bit of help
- end
- end
- f:close()
- print("processing")
- f = io.open(arg[2], "wb")
- -- 0-11 is sync data.
- ffi.copy(buf, "\0\255\255\255\255\255\255\255\255\255\255\0")
- -- 12, 13 and 14 are BCD minute/second/frame and are calculated per sector
- buf[15] = 2 -- CD-XA Mode 2
- -- 16-23 is the subheader. 20-23 is a copy of 16-19.
- -- 16 is file (?). 17 is channel. 18 is submode (bitfield). 19 is coding.
- -- No idea about what file/channel/coding are used for. Maybe audio/video.
- -- For submode, see Mednafen 0.9.41+dfsg sources, src/psx/cdc.cpp line 621.
- -- We set the submode on sectors 12-16 like in PSX discs; the rest as DATA.
- -- Not sure if it makes a difference.
- -- 24-2071 is the data (payload).
- -- 2072-2075 is CRC, calculated over the subheader + data without padding.
- -- Bit-reversed like CRC-32; little-endian.
- -- 2076-2247 is P-parity (Reed-Solomon ECC). Not calculated here.
- -- 2248-2351 is Q-parity (Reed-Solomon ECC). Not calculated here.
- -- For Reed-Solomon details see ECMA-130 and the Mednafen sources.
- local i = 0
- repeat
- do
- local msf_sector = brshift(i, 11) + 150
- buf[14] = msf_sector % 75
- buf[13] = (msf_sector - buf[14]) / 75 % 60
- buf[12] = (msf_sector - buf[13] * 75 - buf[14]) / (75 * 60)
- end
- do
- -- Convert to BCD
- local tmp = buf[12] % 10
- buf[12] = (buf[12] - tmp) / 10 * 16 + tmp
- tmp = buf[13] % 10
- buf[13] = (buf[13] - tmp) / 10 * 16 + tmp
- tmp = buf[14] % 10
- buf[14] = (buf[14] - tmp) / 10 * 16 + tmp
- end
- buf[18] = (i >= 0x6000 and i < 0x8000) and 0x20 -- FORM = 2
- or (i == 0x8000) and 0x09 -- DATA, EOR
- or 0x08 -- DATA
- buf[22] = buf[18]
- ffi.copy(buf + 24, data + i, 2048)
- local crc = CRC(buf)
- buf[2072] = band(crc, 0xFF)
- buf[2073] = band(brshift(crc, 8), 0xFF)
- buf[2074] = band(brshift(crc, 16), 0xFF)
- buf[2075] = band(brshift(crc, 24), 0xFF)
- f:write(ffi.string(buf, 2352))
- i = i + 2048
- if i % 16777216 == 0 then
- collectgarbage()
- end
- until i == size
- f:close()
- print("done")
- end
- return main()
|