Van egy MUPID C2A2 számítógépem, ami képes a BTX (CEPT1) szabvány szerinti Videotext (németül Bildschirmtext) protokoll szerint hálózatról megjeleníthető tartalmat valamint programot letölteni. A BTX megjelenítés elég jól dokumentált, programok is vannak rá, amik oda-vissza konvertálnak. Azonban a programok betöltése BTX terminálon keresztül, úgy tűnik, eltűnt az idők forgatagában.
Egyetlen betölthető program érhető ma el, Norbert Kehrer btx_server megvalósításában, egy Z80-ra írt FIG-FORTH port.
Ez a program rendben betölthető, és fut is.
A BTX protokoll szerint az 1F3C kétbájtos vezérlő kód után következik a betölthető program. A BTX protokoll sajátossága, hogy a 0x20 alatti és 0x7F feletti kódok mindig vezérlőkódok. A konkrét FORTH program esetében az 1F3C kódsor után csak 0x40 és 0x7F közötti bájtok következnek kivéve a blokk végén található utolsó bájtot, ami ugyan 0x20 értéknél nagyobb, de 0x40 értéknél kisebb.
A konkrét program esetében az első 1F3C után 4 bájt következik: 0x40404021 majd kezdődik egy újabb 1F3C blokk, aminek a végén 0x28 található, és ezek után a teljes adatfolyamot egy 0x1A bájt zárja le.
Mindkét 1F3C utáni blokk 4-gyel osztható számú bájtot tartalmaz, a lezáró 0x2* bájttal együtt.
Valószínűleg tehát 6 biten vannak elkódolva a 8 bites adatok, de eddig semmilyen módon nem tudtam az eredeti Z80-as kódot visszanyerni az elkódolt mupidforth fájlból. Próbáltam felvenni a kapcsolatot Norbert Kehrerrel, eddig sikertelenül.
Az kipróbált dekódolási módszereim:
- fogom a 6 bites csoportokat, egymásután írom, majd 8 bitenként mentek belőlük bájtokat. (Kipróbáltam többféle iránnyal is.)
- fogom az első 3 darab 6 bites adatot, ez lesz a bájtok alsó 6 bitje, majd az utolsó 6 bitet szétosztom a bájtok felső 2 bitjére. (Itt is próbáltam különböző irányokkal.)
Mivel ez egy FORTH fordító, konkrétabban a FIG-FORTH Z80-as megvalósításának portja MUPID-ra, így legalább a kulcsszavak, vagy azok egy részének benne kellene lenni a dekódolt fájlban. Megnéztem az eredeti FIG-FORTH fordítót, ott a bináris kód elején olvasható formában vannak a kulcsszavak.
Továbbá a program bejelentkezéskor kiírt szövegének is valahogy benne kellene lennie a helyesen dekódolt fájlban:
Mupid Forth - Norbert Kehrer, April 2014
Z80 fig-FORTH 1.1.8
MUPID version by Norbert Kehrer in 2014Kerestem dokumentációt, nem találtam. Próbáltam német fórumon, de már nem ismerik a konkrét formátumot. A műokos sem tudott segíteni.
Ha van köztetek bárki, aki véletlen tud erről a protokollról, vagy kihívásnak érezné hogy segítsen a kódolás megfejtésében, annak válaszát megköszönném. Ha netán csak ötlete van valakinek, hogy milyen módokon lehet még értelmesen elkódolni 6 biten 8 bites adatokat, azért is hálás lennék.
- 1189 megtekintés
Hozzászólások
Up
- A hozzászóláshoz be kell jelentkezni
Ezt találtam, ha segít: https://gtoal.com/acorn/files/Teletext/Teletext%20Telesoftware%20Transm…
- A hozzászóláshoz be kell jelentkezni
Köszönöm, ezt nem találtam meg, áttanulmányozom.
Azóta találtam még két betölthető programot, az egyik a BASIC, a másik 80 karakteres módba váltja a képernyőt (80Z). Annyit még megtudtam, hogy a MUPID a lemezvezérlőhöz ugyanezzel a BTX protokollal kapcsolódik, tehát, ha valaki vissza tudná fejteni a MUDISK.COM DOS programot, abban lehet, hogy lenne információ. Persze, lehet, hogy nem, ha ezeket a csatolt fájlokat küldi csak a gép felé.
Jelenleg tehát 3 betölthető programom van. Ezek felépítése:
mupidforth: 2 darab programoblokkból áll, az első 4 bájtos 40404021 felépítésű, a második maga a program.
basic: 1 darab programblokkból áll
80Z: 10 darab programblokkból áll, ebben két darab is van, ami a minimális 4 bájtos 40404021 sorozat.
Itt azonban van egy 4 bájtos blokk, ahol az első 3 bájt nem a szokásos 404040, vagyis úgy tűnik, már 4 bájton is lehet érdemi adatot kódolni.
Mivel már összesen 13 programblokkunk van, feltűnik, hogy az utolsó bájt értéke 0x21 vagy 0x22 vagy 0x28 lehet. És az is feltűnik, hogy a 0x21 végződés csak a 40404021 blokkban van. Ha bármilyen más adat van a blokkban, akkor 0x22 vagy 0x28 az utolsó bájt.
És még egy szomorú hír: A blokkok hossza nem mindig 4-gyel osztható. Sőt! Egy esetben páratlan szám!
A műokos egy ötlete volt, hogy talán 2x6 bit kódol egy bájtot. Ez esetben 4 bit lehet egy-egy nibble, a maradék két bit lehet paritás, CRC vagy más.
Mivel a 6 bites adatok között szerepel a 000000 és a 000001 is, emiatt nem hiszem, hogy 4 bites adatkódolás mellett lenne benne paritás vagy CRC bit.
Egy tippje volt még a műokosnak, hogy egy bit jelölheti, hogy felső vagy alsó nibble az adat. Mondjuk ha a bit 1, akkor alsó, ha 0, akkor felső. Ez esetben lenne egy bit, ami folyamatosan váltakozik. Ilyen bit nincs. De ha ez így lenne, akkor rögtön lehetne egy olyan tömörítést vinni a kódolásba, hogyha az alsó és felső nibble azonos, akkor rögtön csak a második bájtot tárolják le, és ezt a jelző bitből dekódoláskor észre is lehetne venni. Ez esetben nem lesz ez a bit sem folyamatosan váltakozó, a bájtok száma sem lesz innentől mérvadó, és egy ilyen tömörítés mellett szerintem esély sincs nagyon a dekódolás megfejtésére.
Ha mind a hat adatbit az elkódolt bájtok bitjeből áll, akkor a kódolásnak kis kavarással BASE64-nek kellene lennie, max a felhasznált karakterek és max bájtsorrendek változhatnak. Próbáltam így is, nem lett értelmes a dekódolt fájl. A BASIC interpreter miatt nagy a valószínűsége, hogy helyes dekódolás után a bináris fájlban meg kellene jelennie a BASIC kulcsszavaknak. Bár, mint kiderült a BASIC egy nagy része már a PROM-ban van, így ez sem feltétlen igaz.
Próbálom megszerezni a három program dekódolt változatát, egyelőre sikertelenül. Ha meglenne legalább a dekódolt méret, már az sokat segítene, de nincs.
Egyelőre tehát ez a helyzet, és további információ nélkül nem hiszem, hogy előbbre tudnék jutni.
A leírást átolvasom, hátha lesz benne ötlet, támpont.
Búcsúzóul készítettem még statisztikát, hogy melyik bit hányszor 1, remélve, hogy valamelyik bit majd mutat valami érdekeséget:
0. 7236
1. 7096
2. 7108
3. 7140
4. 7247
5. 7165
6. 16087
7. 0
Hát, ez eléggé egyenletes eloszlásnak tűnik az alsó 6 bitre, bár 50% alatt. De úgy tűnik, ettől sem jutottunk előbbre.
- A hozzászóláshoz be kell jelentkezni
A btx-server/mupidforth-ot sikerült dekódolnom (valamennyire).
A végeredmény Forth programnak néz ki, de nem próbáltam futtatni.
mupidforth "btx" file két részböl áll:
- képernyö
- adat
1, képernyö, kb:
FIG-Forth ported to he MUPID II by Norbert Kehrer in April 2014
WWW: http://web.utanet.at/nkehrer
Email: norbert_kehrer@yahoo.de
Loading. Please wait2, adat
2.1, header:
hex "1F 3C 40 40 40 21 1F 3C 48 44 40" (vagy hosszabb 4-8-12-16... bájttal)
2.2 adat stream
4x6 bit van 3x8 bit-be csomagolva.
Egy btx bájt max 0..127, de a 0..63 mindig vezérlökódok a program streamben is. Tehát marad 64...127 minden btx bájtban.
Programkóddal leírva (Python):
# Convert 4 bytes to four 6-bit values (Offset-64)
v = [((c - 64) & 0x3F) for c in data[i:i+4]]
# Pack 4x6 bits into 3x8 bits.
decoded_bytes.append((v[0] << 2) | (v[1] >> 4))
decoded_bytes.append(((v[1] & 0x0F) << 4) | (v[2] >> 2))
decoded_bytes.append(((v[2] & 0x03) << 6) | v[3])2.3 stream vége. hex "28 1A"
Teljes Python programlista:
def extract_mupid_forth(input_file):
binary_marker_txt = "1F 3C 40 40 40 21 1F 3C 48 44 40"
binary_marker = bytes.fromhex(binary_marker_txt.replace(" ", ""))
with open(input_file, 'rb') as f:
content = f.read()
text_data = content.split(binary_marker)[0]
with open(f'mupidforth.output.1.txt', 'wb') as text_file:
text_file.write(text_data)
# Check if the binary marker is present in the file
if binary_marker in content:
print("Binary marker found in the file.")
binary_data_start = content.index(binary_marker)
data = content[binary_data_start + len(binary_marker) :]
# Ensure length is a multiple of 4 for the 4-for-3 decoding
data = data[:len(data) - (len(data) % 4)]
decoded_bytes = bytearray()
for i in range(0, len(data), 4):
# if next byte is not in the range of 64 to 127, then we have reached the end of the data, as the encoded data only uses characters in that range. We can stop decoding at this point.
if any(c < 64 for c in data[i:i+4]):
break
# Convert 4 bytes to four 6-bit values (Offset-64)
v = [((c - 64) & 0x3F) for c in data[i:i+4]]
# Pack 4x6 bits into 3x8 bits.
decoded_bytes.append((v[0] << 2) | (v[1] >> 4))
decoded_bytes.append(((v[1] & 0x0F) << 4) | (v[2] >> 2))
decoded_bytes.append(((v[2] & 0x03) << 6) | v[3])
with open(f'mupidforth.output.2.bin', 'wb') as out_file:
out_file.write(decoded_bytes)
else:
print("Binary marker NOT found in the file.")
return
# Usage
extract_mupid_forth('mupidforth')- A hozzászóláshoz be kell jelentkezni
Nagyon köszönöm! Azt azért áruld el kérlek, hogy mi alapján döntöttél úgy, hogy az 1F 3C utáni 3 bájtot még át kell ugrani? Mert úgy tűnik át kell, de nem tudom, hogyan jöttél erre rá? Én ezeket is beleszámoltam, és így vagy kettőt, vagy 4-et ugrottam, de hármat soha. :)
Mindenképpen legalább az kiderült, hogy valóban, maguk az adatok BASE64 szerűen vannak kódolva, valamint a Mupid Teleprogram formátum az 1F 3C után még definiál valamit ... talán betöltési címet? De a 80Z kódban 2 darab ilyen kódblokk is van, fura lenne, hogy betölt valamit, majd ugyanoda rátölt valami mást. A BASIC elején meg egyáltalán nincs.
Mindenesetre ez nagy előrelépés! Még egyszer nagyon köszönöm, és gratulálok hozzá! :) Ezek alapján már el lehet kezdeni a maradék visszafejtését!
Ha valakinek még van kedve küzdeni, a következő kérdés, hogy az 1F 3C utáni 3 bájt mit jelent, valamint, hogy a lezáró 21, 22, 28 mit jelenthet.
- A hozzászóláshoz be kell jelentkezni
fura lenne, hogy betölt valamit, majd ugyanoda rátölt valami mást.
Abszolút nem fura! ZX Spectrum és Commodore 64 alatt is pl a képernyő memória, ahonnan a kirajzolás történt, a normál RAM része volt, egy speciális memóraiterület, fix koordinátákkal. A kor betöltői rendszeresen játszottak azzal, hogy kazettáról/diskről azt a memóriatartományt töltötték be, így hozták be mondjuk a betöltőképet, majd mókolt a háttérben, és a képváltáshoz ugyanarra a memória területre betöltöttek valami mást. Nyilván ennek a technológiának megvoltak a maga korlátai, de volt értelme. A mechanika lényege az volt, hogy a PRG állományok első két byte-ja a betöltési címet kódolta, a kazetta/disk kezeő ROM rutinok innen tudták, hogy hova kell betölteni a tartalmat. Mivel a képernyő memóriaterületei nem voltak védettek, nem ellenőrzött senki semmit, egyszerűen felülírták a koordináátokn a memóratartalmat.
Ugyanígy volt moduláris/többfunkciós sok program, kiválasztottad a funkciót, az elugrott a felülírandó területről a betöltő kódra, és egyszerűen kicserélte a memóriatartalmat, RET helyett pedig regiszterből/ugrótáblából kivette, hogy hova kell visszaugrani. Ha jól volt megírva a program, még az is lehetséges volt, hogy a RET/RTS eleve jó helyre ugrott vissza, ha a kódnak az a szakasza amúgy megegyezett a modulokban.
Nagyon sok olyan kreaktív kódolási mechanizmus volt annak idején használatban a memóriaterületek kapcsán, amik mára teljesen kivesztek a köztudatból.
- A hozzászóláshoz be kell jelentkezni
Sikerült betöltenem az első saját készítésű programomat a MUPID számítógépre gaborgabor módszerével a BTX protokollon keresztül.
Úgy tűnik, az 1F 3C kódsorozat után van 3 bájt, aminek alsó 6 bitje kódol valamit. Jelenleg azt tippelem, hogy ez egy betöltési cím, de ez még nem biztos.
Innentől a bájtok alsó 6 bitjén a betöltendő adat, míg a felső két bit kötelezően 01. 4 bájtonként kapunk 3 betöltendő bájtot.
Itt nem tudom, mi van, ha már nincs 4 bájt hátra. Általában a bájtok száma 4-gyel osztható, de néha nem.
A legvégén pedig a lezáró bájt felső 3 bitje 001, míg az alsó 5 bit valószínűleg a következő műveletre vonatkozik. A saját programom csak akkor fut le, ha ebben a 3. bit 1-es, azaz a lezáró bájt például 0x28. De ugyanígy lefut, ha 0x2A. Azonban mondjuk 0x22 esetén nem látom a futás eredményét, így valószínűleg akkor csak a betöltés történik meg.
Mivel a MUPID számítógépnek 128KB memóriája van, így egy abszolút cím megadásához nem 16, hanem 17 bit kell. Az 1F 3C után pedig 18 hasznos bit következik, ami ezek szerint lehet, hogy csak egy címet definiál.
Sajnos a MUPID ROM rutinok címei, és belső működése sem igazán dokumentált, így még nem tudok egy karakter kiírni a képernyőre. Szerencsére a FORTH segítségével találtam olyan memóriaterületet, amire ha adatot írok, annak egyértelmű látványos eredménye van.
Félek, hogy innentől már csak tesztelgetéssel lehet kideríteni az első 3 bájt és a lezáró bitek jelentését, ami fizikai gép nélkül nem megoldható, így ez a szál elérte lehetőségei határát.
Nagyon köszönöm az eddigi segítséget. Nem jelölöm lezártnak a szálat, mert ha bárkinek bármilyen ötlete vagy információja van, azt továbbra is örömmel fogadom, valamint elképzelhető, hogy merülnek még fel új kérdéses pontok.
- A hozzászóláshoz be kell jelentkezni
Úgy tűnik, az 1F 3C kódsorozat után van 3 bájt, aminek alsó 6 bitje kódol valamit. Jelenleg azt tippelem, hogy ez egy betöltési cím, de ez még nem biztos.
Szerintem a 3 byte úgy betöltési cím, hogy 2 byte a memóriacím alsó és felső bájtja, a 3. byte pedig valamilyen szegmensazonosító lehet. 128K memóriához nagyon fura nekem a 6 bites címzés, nem hiszem, hogy 64 byte-onként lenne felosztva egy ekkora memória. Sokkal reálisabbnak tűnik nekem az, hogy van 2 64 kilobyte-os page, és ezt azonosítod valahogy.
Nem ismerem a MUPID-ot, de ha a ROM tartalmát átfordítod Z80 assemblybe az nem ad támpontot? Riktán írnak ROM-ot másban, mint ASM-ben. Ha mást nem, az egyes rutinok határait el lehet választani a RET utasítások mentén
- A hozzászóláshoz be kell jelentkezni
A 6 bit azért 6 bit, mert az egész a BTX adatfolyam része, ami a 0x20 alatti bájtokat speciális vezérlőkódnak tekinti, így az 1F 3C kód után csak 0x1F feletti bájtok jöhetnek, a minták alapján pedig csak 0x3F felettiek, vagyis az első két bit fix 01. Vagyis az a 3 bájt is csak 3x6 bit.
A ROM visszafordítását fogom tanulmányozni, de az azért nekem nem kis feladat.
- A hozzászóláshoz be kell jelentkezni
Senkinek se kis feladat. Valahogy próbálj meg leírást szerezni a gépről, és felrajzolni egy-több memória térképet.
Illetve, amit tudok még javasolni, hogy az Enterprise 128k -t nézd át, tudom, hogy ez másik gép, de egyrészt az is Z80 alapú, másrészt hátha vannak közös megoldások a ROM-ban.
- A hozzászóláshoz be kell jelentkezni
Köszönöm. Úgy tűnik, nagyon más út nincs. Dokumentációt, amennyit lehetett, begyűjtöttem. Nem reménykedem, hogy találok még. Ezen kívül már tényleg csak a ROM marad. Azért annyi könnyebbség van, hogyha egy rutinra van tippel, akkor tudom élesben tesztelni.
- A hozzászóláshoz be kell jelentkezni
Rendkivül érdekes feladvány.
Online semmit se találtam az 1f 3C részleteiröl, és mi lehet a mágikus 3 byte a headerben (vagy 7 byte). Csak azt hogy "Mupid-Teleprogramm-Format" de ezt már tudod.
Spekulációk:
- gyanítom a headerben a 0x40,0x40,0x40-et 0,0,0-nak kell értelmezni (vagyis -0x40 mindegyikböl)
- sejtés, de a load address és esetleg a start address lehet benne
- a load address vagy 16bit-es "finom" cím, vagy csak 1k/4k/8k/16k blokk indexe
- bár 128k memórája volt a mupid-nak, de lehet programot csak az egyik 64k-os részbe töltötte, a többi rendszer meg képernyö memória
A visszafejtett 3 példaprogramról:
- a "basic" program is assemblynek néz ki, talán egy basic interpreter? vannak benne basic kulcsszavak. 12k elég lehet egy egyszerübb basichez.
- a "80z" több külön kis darabból áll, amiböl három az 0 byte. az egyik darab eleje teljesen értelemes z80 assembly, a többit nem néztem.
Itt a kis dekódoló progim v2 változata:
def decode_btx(input_file):
binary_marker_txt = "1F 3C"
binary_marker = bytes.fromhex(binary_marker_txt.replace(" ", ""))
segment_index = 0
with open(input_file, 'rb') as f:
content = f.read()
while True:
binary_data_start = content.find(binary_marker)
if binary_data_start == -1:
break
segment_index += 1
if segment_index > 100:
print("Too many segments found, stopping to prevent infinite loop.")
break
binary_data_start += len(binary_marker)
binary_data_end = next(
(i for i in range(binary_data_start, len(content)) if content[i] < 0x40),
len(content)
)
data=content[binary_data_start:binary_data_end]
content = content[binary_data_end:]
# skip first 3 bytes of byte in data variableci
bin_header_bytes = data[:3]
data = data[3:]
# Ensure length is a multiple of 4 for the 4-for-3 decoding
data = data[:len(data) - (len(data) % 4)]
decoded_bytes = bytearray()
for i in range(0, len(data), 4):
if any(c < 64 for c in data[i:i+4]):
break
# Convert 4 bytes to four 6-bit values (Offset-64)
v = [((c - 64) & 0x3F) for c in data[i:i+4]]
# Pack 4x6 bits into 3x8 bits.
decoded_bytes.append((v[0] << 2) | (v[1] >> 4))
decoded_bytes.append(((v[1] & 0x0F) << 4) | (v[2] >> 2))
decoded_bytes.append(((v[2] & 0x03) << 6) | v[3])
out_file_name = f'{input_file}.out.{segment_index}.bin'
bin_header_bytes_as_hex_str = ' '.join(f'{b:02X}' for b in bin_header_bytes)
print(f"Writing decoded segment to {out_file_name} with header bytes: {bin_header_bytes_as_hex_str}")
with open(out_file_name, 'wb') as out_file:
out_file.write(decoded_bytes)
# Usage
decode_btx('mupidforth')
decode_btx('btx-basic.btx')
decode_btx('80z.btx')- A hozzászóláshoz be kell jelentkezni
Közben nagyot léptem előre! A BASIC leírásban vannak gépi rutinok is megemlítve, így már tudok a képernyőre karaktereket írni. Ezzel sikerült megállapítanom a betöltött kód helyét a memóriában, abból pedig az 1F 3C utáni 3 bájt hatását. Ennek a 3 bájtnak az alsó 6 bitjei egymásután adnak 18 bitet. Ebből:
Az első két bit valószínűleg a lapot adja meg, vagy figyelmen kívül marad, ezt még nem tudom. A BASIC a 01-es lapra tölti be magát, a FORTH a 00-ás lapra. Vagy mindkettő ugyanoda, ha figyelmen kívül hagyódik. Mivel a programjaim egyelőre csak a PC értékét tudták lekérni, így a lapot nem látom.
A további 16 bit azonban egyértelműen a betöltési terület kezdőcímét határozzák meg. Ezzel a 3 bájt el is fogyott.
A BASIC értelmezőt próbáltam betölteni, be is tölti, csak a betöltés végén nem elindul, hanem folytatni akarja a betöltést egy C nevű fájllal, amim nincs meg.
Lehet, hogy lemezes környezetben ez elindulna, még ott sem járok.
A 80Z pedig betöltve 80 karakteres üzemmódba vált.
Amúgy létezik egy MUPID emulátor is a MAME projektben, de eléggé korlátozott, például még képernyője sincs, de a bootolás folyamatához hasznos lehet. Igaz, én nézegettem, sokra nem mentem vele.
- A hozzászóláshoz be kell jelentkezni