Compare commits

6 Commits

Author SHA1 Message Date
Philip Smart
8ef9652935 Updates to MZQD Tool for Sharp MZ Series QD image creation 2026-04-01 17:20:52 +01:00
Philip Smart
c0b9a6a5af Added MZQD tool to create QD files for Sharp MZ Series 2026-04-01 16:42:12 +01:00
Philip Smart
113b836c91 Added JLCPCB Positions and Production files 2026-04-01 16:40:21 +01:00
Philip Smart
2b89372f29 Added JLCPCB bom list 2026-04-01 16:36:34 +01:00
Philip Smart
2094666e6b Licenses 2026-03-31 13:01:36 +01:00
Philip Smart
665b494bd2 Licenses 2026-03-31 12:32:49 +01:00
23 changed files with 592 additions and 385 deletions

18
README.ja.md vendored
View File

@@ -317,3 +317,21 @@ picoZ80/pico6502 のハードウェア設計、ファームウェア、および
**picoZ80**、**pico6502**、**engineers@work** の名称は Philip Smart の商標です。帰属表示、商標、および盗用防止の条項の詳細は [NOTICE](NOTICE) ファイルをご覧ください。
ライセンス全文: [LICENSE](LICENSE) | [LICENSE-HARDWARE.txt](LICENSE-HARDWARE.txt) | [LICENSE-SOFTWARE.txt](LICENSE-SOFTWARE.txt)
---
## 無線規制に関する注意事項
**本デバイスは 2.4 GHz ISM バンドで送信する ESP32-S3-PICO-1 無線モジュールを搭載しており、世界各国の無線周波数規制(米国の FCC Part 15 Subpart C、欧州連合の無線機器指令 2014/53/EU を含む)において意図的放射器に該当します。**
ESP32-S3-PICO-1 モジュール自体は既存の規制認証FCC、CE など)を取得していますが、そのモジュールレベルの認証は、**モジュールを組み込んだ完成品に自動的に適用されるものではありません**。事前認証モジュールの免除規定は、**個人の趣味愛好家**が**個人使用、実験、または教育目的**で少数のデバイスを製作する場合に、個別の機器認可を取得せずに行うことを許可するものです。
### 重要な制限事項
- 組み立てられたデバイスは、完成品が独自にテストされ、該当する管轄区域で機器認可FCC ID、認定機関による CE マーキング評価)を取得しない限り、**第三者への販売、販売の申し出、贈与、またはその他の方法での配布を行ってはなりません**。
- 個人使用のために少数を製作することは、趣味愛好家および実験使用の規定FCC §15.23)に基づき、デバイスが有害な干渉を引き起こさない限り、一般的に許可されています。
- 規制要件は国によって異なります。米国外の製作者は、適用される規則について自国の無線周波数当局に確認してください。
### 製作者の責任
本設計に基づいて製作されたデバイスが、管轄区域内の適用されるすべての無線周波数規制に準拠することは、製作者の単独の責任です。著者は本設計を個人使用、教育、および趣味愛好家向けに提供しており、本設計から製作されたデバイスが商業的配布の規制要件を満たすことについて、いかなる表明も行いません。

18
README.md vendored
View File

@@ -317,3 +317,21 @@ The firmware and software are open-source under the GPL v3. The hardware designs
The names **picoZ80**, **pico6502**, and **engineers@work** are trademarks of Philip Smart. See the [NOTICE](NOTICE) file for full attribution, trademark, and anti-passing-off terms.
Full licence texts: [LICENSE](LICENSE) | [LICENSE-HARDWARE.txt](LICENSE-HARDWARE.txt) | [LICENSE-SOFTWARE.txt](LICENSE-SOFTWARE.txt)
---
## Wireless Regulatory Notice
**This device incorporates an ESP32-S3-PICO-1 wireless module that transmits in the 2.4 GHz ISM band, making it an intentional radiator under radio-frequency regulations worldwide (including FCC Part 15 Subpart C in the United States, and the Radio Equipment Directive 2014/53/EU in the European Union).**
Although the ESP32-S3-PICO-1 module itself carries pre-existing regulatory certifications (FCC, CE, and others), those module-level certifications **do not automatically extend to a finished product** that incorporates the module. The pre-certified module exemption permits **individual hobbyists** to build a limited number of devices for **personal, experimental, or educational use** without obtaining separate equipment authorisation.
### Important Limitations
- Assembled devices **must not be sold, offered for sale, gifted, or otherwise distributed** to third parties unless the finished product has been independently tested and granted its own equipment authorisation (e.g. FCC ID, CE marking with a Notified Body assessment) in the relevant jurisdiction.
- Building this project for personal use in limited quantities is generally permitted under hobbyist and experimental-use provisions (e.g. FCC §15.23), provided the device does not cause harmful interference.
- Regulatory requirements vary by country. Builders outside the United States should consult their national radio-frequency authority for applicable rules.
### Builder's Responsibility
It is the builder's sole responsibility to ensure that any device constructed from these designs complies with all applicable radio-frequency regulations in their jurisdiction. The author provides these designs for personal, educational, and hobbyist use and makes no representation that a device built from them satisfies the regulatory requirements for commercial distribution.

15
WIRELESS.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# Wireless Regulatory Notice
**This device incorporates an ESP32-S3-PICO-1 wireless module that transmits in the 2.4 GHz ISM band, making it an intentional radiator under radio-frequency regulations worldwide (including FCC Part 15 Subpart C in the United States, and the Radio Equipment Directive 2014/53/EU in the European Union).**
Although the ESP32-S3-PICO-1 module itself carries pre-existing regulatory certifications (FCC, CE, and others), those module-level certifications **do not automatically extend to a finished product** that incorporates the module. The pre-certified module exemption permits **individual hobbyists** to build a limited number of devices for **personal, experimental, or educational use** without obtaining separate equipment authorisation.
## Important Limitations
- Assembled devices **must not be sold, offered for sale, gifted, or otherwise distributed** to third parties unless the finished product has been independently tested and granted its own equipment authorisation (e.g. FCC ID, CE marking with a Notified Body assessment) in the relevant jurisdiction.
- Building this project for personal use in limited quantities is generally permitted under hobbyist and experimental-use provisions (e.g. FCC §15.23), provided the device does not cause harmful interference.
- Regulatory requirements vary by country. Builders outside the United States should consult their national radio-frequency authority for applicable rules.
## Builder's Responsibility
It is the builder's sole responsibility to ensure that any device constructed from these designs complies with all applicable radio-frequency regulations in their jurisdiction. The author provides these designs for personal, educational, and hobbyist use and makes no representation that a device built from them satisfies the regulatory requirements for commercial distribution.

View File

@@ -0,0 +1,118 @@
Designator,Mid X,Mid Y,Rotation,Layer
AE1,72.05,-91.49,180.0,top
C1,69.69,-99.61,90.0,top
C10,80.09,-91.44,90.0,top
C11,80.05,-97.81,90.0,top
C12,81.05,-97.81,90.0,top
C13,80.59,-102.56,90.0,top
C14,80.6,-104.44,270.0,top
C15,80.16,-118.89,180.0,top
C16,78.613,-115.316,180.0,bottom
C17,78.613,-113.792,180.0,bottom
C18,78.105,-128.877,90.0,bottom
C19,76.581,-126.492,0.0,bottom
C2,69.69,-104.14,270.0,top
C20,75.946,-127.917,90.0,bottom
C21,76.962,-127.917,90.0,bottom
C22,72.644,-109.601,270.0,bottom
C23,74.168,-111.506,0.0,bottom
C24,73.787,-117.602,180.0,bottom
C25,74.803,-123.599,270.0,bottom
C26,73.787,-123.599,270.0,bottom
C27,72.771,-127.889,90.0,bottom
C28,73.914,-127.889,90.0,bottom
C29,74.93,-127.917,90.0,bottom
C3,70.4,-106.03,180.0,top
C30,70.358,-115.189,180.0,bottom
C31,70.345,-113.665,180.0,bottom
C32,70.739,-116.967,90.0,bottom
C33,72.291,-122.428,180.0,bottom
C34,72.291,-123.444,180.0,bottom
C35,72.235,-124.46,180.0,bottom
C36,72.235,-125.476,180.0,bottom
C37,71.755,-127.889,90.0,bottom
C38,72.235,-126.492,180.0,bottom
C39,69.723,-116.967,90.0,bottom
C4,72.29,-106.03,0.0,top
C40,75.22,-140.01,180.0,bottom
C41,80.88,-133.38,270.0,top
C42,79.77,-138.27,270.0,bottom
C5,69.878,-136.525,0.0,top
C6,73.57,-95.78,180.0,top
C7,73.787,-135.791,270.0,top
C8,75.692,-119.225,90.0,top
C9,78.47,-90.94,0.0,top
J1,75.179,-140.322,0.0,top
J3,75.08,-100.475,180.0,bottom
L1,76.515,-92.01,0.0,top
L2,78.46,-92.01,0.0,top
L3,77.978,-124.013,270.0,bottom
L4,77.0635,-117.348,180.0,bottom
R1,67.183,-95.504,0.0,top
R10,67.181,-118.237,0.0,top
R11,67.183,-123.317,0.0,top
R12,67.183,-125.857,0.0,top
R13,67.183,-128.397,0.0,top
R14,67.183,-130.937,0.0,top
R15,67.18,-133.49,180.0,top
R16,67.19,-136.0,180.0,top
R17,67.17,-138.56,180.0,top
R18,67.19,-141.09,180.0,top
R19,69.19,-142.35,180.0,top
R2,67.183,-97.917,0.0,top
R20,73.787,-133.475,90.0,top
R21,75.01,-91.54,90.0,top
R22,77.4,-95.78,0.0,top
R23,75.48,-95.78,0.0,top
R24,77.341,-134.62,180.0,top
R25,77.345,-135.6106,180.0,top
R26,80.15,-120.04,180.0,top
R27,80.89,-142.37,0.0,top
R28,82.931,-95.377,180.0,top
R29,82.933,-97.917,180.0,top
R3,67.183,-100.457,0.0,top
R30,82.929,-100.457,180.0,top
R31,82.931,-102.997,180.0,top
R32,82.931,-105.537,180.0,top
R33,82.933,-108.077,180.0,top
R34,82.931,-110.617,180.0,top
R35,82.929,-113.157,180.0,top
R36,82.931,-115.697,180.0,top
R37,82.929,-118.237,180.0,top
R38,82.931,-120.777,180.0,top
R39,82.933,-125.857,0.0,top
R4,67.181,-102.997,0.0,top
R40,82.929,-128.397,0.0,top
R41,82.92,-130.93,0.0,top
R42,82.93,-133.5,0.0,top
R43,82.93,-135.99,0.0,top
R44,82.93,-138.56,0.0,top
R45,82.93,-141.09,0.0,top
R46,80.264,-111.76,270.0,bottom
R47,80.88,-133.38,90.0,bottom
R48,77.724,-109.599,90.0,bottom
R49,78.105,-126.998,270.0,bottom
R5,67.183,-105.537,0.0,top
R50,75.692,-109.599,90.0,bottom
R51,76.708,-109.599,270.0,bottom
R52,68.88,-129.05,270.0,bottom
R53,69.89,-129.05,270.0,bottom
R54,74.676,-109.599,90.0,bottom
R55,74.166,-112.522,0.0,bottom
R56,70.612,-109.601,90.0,bottom
R57,71.628,-109.601,90.0,bottom
R58,72.39,-113.286,270.0,bottom
R59,69.596,-109.601,90.0,bottom
R6,67.19,-108.08,180.0,top
R60,72.15,-111.07,180.0,bottom
R7,67.183,-110.617,0.0,top
R8,67.183,-113.157,0.0,top
R9,67.183,-115.697,0.0,top
U2,72.115,-114.4,270.0,top
U3,75.04,-100.98,0.0,top
U4,75.035,-126.2945,270.0,top
U5,78.359,-114.365,180.0,top
U6,75.0515,-114.874,180.0,bottom
U7,76.97,-134.6925,270.0,bottom
Y1,71.036,-134.179,0.0,top
Y2,71.05,-134.18,180.0,bottom
1 Designator Mid X Mid Y Rotation Layer
2 AE1 72.05 -91.49 180.0 top
3 C1 69.69 -99.61 90.0 top
4 C10 80.09 -91.44 90.0 top
5 C11 80.05 -97.81 90.0 top
6 C12 81.05 -97.81 90.0 top
7 C13 80.59 -102.56 90.0 top
8 C14 80.6 -104.44 270.0 top
9 C15 80.16 -118.89 180.0 top
10 C16 78.613 -115.316 180.0 bottom
11 C17 78.613 -113.792 180.0 bottom
12 C18 78.105 -128.877 90.0 bottom
13 C19 76.581 -126.492 0.0 bottom
14 C2 69.69 -104.14 270.0 top
15 C20 75.946 -127.917 90.0 bottom
16 C21 76.962 -127.917 90.0 bottom
17 C22 72.644 -109.601 270.0 bottom
18 C23 74.168 -111.506 0.0 bottom
19 C24 73.787 -117.602 180.0 bottom
20 C25 74.803 -123.599 270.0 bottom
21 C26 73.787 -123.599 270.0 bottom
22 C27 72.771 -127.889 90.0 bottom
23 C28 73.914 -127.889 90.0 bottom
24 C29 74.93 -127.917 90.0 bottom
25 C3 70.4 -106.03 180.0 top
26 C30 70.358 -115.189 180.0 bottom
27 C31 70.345 -113.665 180.0 bottom
28 C32 70.739 -116.967 90.0 bottom
29 C33 72.291 -122.428 180.0 bottom
30 C34 72.291 -123.444 180.0 bottom
31 C35 72.235 -124.46 180.0 bottom
32 C36 72.235 -125.476 180.0 bottom
33 C37 71.755 -127.889 90.0 bottom
34 C38 72.235 -126.492 180.0 bottom
35 C39 69.723 -116.967 90.0 bottom
36 C4 72.29 -106.03 0.0 top
37 C40 75.22 -140.01 180.0 bottom
38 C41 80.88 -133.38 270.0 top
39 C42 79.77 -138.27 270.0 bottom
40 C5 69.878 -136.525 0.0 top
41 C6 73.57 -95.78 180.0 top
42 C7 73.787 -135.791 270.0 top
43 C8 75.692 -119.225 90.0 top
44 C9 78.47 -90.94 0.0 top
45 J1 75.179 -140.322 0.0 top
46 J3 75.08 -100.475 180.0 bottom
47 L1 76.515 -92.01 0.0 top
48 L2 78.46 -92.01 0.0 top
49 L3 77.978 -124.013 270.0 bottom
50 L4 77.0635 -117.348 180.0 bottom
51 R1 67.183 -95.504 0.0 top
52 R10 67.181 -118.237 0.0 top
53 R11 67.183 -123.317 0.0 top
54 R12 67.183 -125.857 0.0 top
55 R13 67.183 -128.397 0.0 top
56 R14 67.183 -130.937 0.0 top
57 R15 67.18 -133.49 180.0 top
58 R16 67.19 -136.0 180.0 top
59 R17 67.17 -138.56 180.0 top
60 R18 67.19 -141.09 180.0 top
61 R19 69.19 -142.35 180.0 top
62 R2 67.183 -97.917 0.0 top
63 R20 73.787 -133.475 90.0 top
64 R21 75.01 -91.54 90.0 top
65 R22 77.4 -95.78 0.0 top
66 R23 75.48 -95.78 0.0 top
67 R24 77.341 -134.62 180.0 top
68 R25 77.345 -135.6106 180.0 top
69 R26 80.15 -120.04 180.0 top
70 R27 80.89 -142.37 0.0 top
71 R28 82.931 -95.377 180.0 top
72 R29 82.933 -97.917 180.0 top
73 R3 67.183 -100.457 0.0 top
74 R30 82.929 -100.457 180.0 top
75 R31 82.931 -102.997 180.0 top
76 R32 82.931 -105.537 180.0 top
77 R33 82.933 -108.077 180.0 top
78 R34 82.931 -110.617 180.0 top
79 R35 82.929 -113.157 180.0 top
80 R36 82.931 -115.697 180.0 top
81 R37 82.929 -118.237 180.0 top
82 R38 82.931 -120.777 180.0 top
83 R39 82.933 -125.857 0.0 top
84 R4 67.181 -102.997 0.0 top
85 R40 82.929 -128.397 0.0 top
86 R41 82.92 -130.93 0.0 top
87 R42 82.93 -133.5 0.0 top
88 R43 82.93 -135.99 0.0 top
89 R44 82.93 -138.56 0.0 top
90 R45 82.93 -141.09 0.0 top
91 R46 80.264 -111.76 270.0 bottom
92 R47 80.88 -133.38 90.0 bottom
93 R48 77.724 -109.599 90.0 bottom
94 R49 78.105 -126.998 270.0 bottom
95 R5 67.183 -105.537 0.0 top
96 R50 75.692 -109.599 90.0 bottom
97 R51 76.708 -109.599 270.0 bottom
98 R52 68.88 -129.05 270.0 bottom
99 R53 69.89 -129.05 270.0 bottom
100 R54 74.676 -109.599 90.0 bottom
101 R55 74.166 -112.522 0.0 bottom
102 R56 70.612 -109.601 90.0 bottom
103 R57 71.628 -109.601 90.0 bottom
104 R58 72.39 -113.286 270.0 bottom
105 R59 69.596 -109.601 90.0 bottom
106 R6 67.19 -108.08 180.0 top
107 R60 72.15 -111.07 180.0 bottom
108 R7 67.183 -110.617 0.0 top
109 R8 67.183 -113.157 0.0 top
110 R9 67.183 -115.697 0.0 top
111 U2 72.115 -114.4 270.0 top
112 U3 75.04 -100.98 0.0 top
113 U4 75.035 -126.2945 270.0 top
114 U5 78.359 -114.365 180.0 top
115 U6 75.0515 -114.874 180.0 bottom
116 U7 76.97 -134.6925 270.0 bottom
117 Y1 71.036 -134.179 0.0 top
118 Y2 71.05 -134.18 180.0 bottom

View File

@@ -0,0 +1,38 @@
Designator,Footprint,Quantity,Value,LCSC Part #
AE1,Walsin_RFANT3216120A5T_3216,1,Chip Antenna,C127629
"C1, C6",0402,2,22uF/10V,C3845593
"C10, C9",0402,2,1.5pF,C2980160
"C11, C14, C15, C2, C20, C25, C26, C27, C28, C3, C32, C33, C34, C35, C36, C37, C38, C39, C4, C40, C42, C8",0402,22,100nF,C1525
"C12, C22, C41",0402,3,10uF,C307415
C13,0402,1,1uF/6.3V,C314234
"C16, C17",0603,2,22uF,C2762594
"C18, C19, C21, C29",0402,4,4.7uF,C318563
C23,0402,1,6.8pF,C318598
C24,0805,1,100uF,C6882730
C30,0603,1,10uF,C1691
C31,0603,1,1uF,C5199872
"C5, C7",0402,2,15pF,C106997
J1,USB_Micro-B_Amphenol_10103594-0001LF_Horizontal,1,USB_B_Mini,C428495
J2,PinHeader_1x06_P1.00mm_Vertical,1,JST Debug,
J3,MOLEX_104031-0811,1,SD Drive,C585350
L1,0402,1,6.8nH,C882467
L2,0402,1,2.7nH,C412269
L3,0805,1,3.3u,C48888263
L4,0603,1,2.2uH/1.05A,C337911
"R1, R17, R18, R19, R2, R27, R28, R29, R3, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R4, R40, R44, R45, R5, R52, R53",0402,26,22R,C2906914
"R10, R11, R12, R13, R14, R20, R26, R7, R8, R9",0402,10,1K,C11702
"R15, R16, R21, R41, R42, R43, R6",0402,7,0R,C17168
"R22, R23, R46, R50, R51, R54, R56, R57, R59, R60",0402,10,10K,C60490
"R24, R25",0402,2,27R,C5151586
"R47, R48",0402,2,47K,C25792
R49,0402,1,33R,C25105
R55,0402,1,200K,C114763
R58,0402,1,44.2K,C853281
U1,DIP-40_W15.24mm_Extender_NoCourtyard_SmallPad,1,EXTENDER,
U2,WSON-8-1EP_6x5mm_P1.27mm_EP3.4x4.3mm,1,W25Q128JVPIQ,C190862
U3,QFN-56-1EP_7x7mm_P0.4mm_EP4x4mm,1,ESP32-S3-PICO-1 N8R8,C7545129
U4,RP2350-QFN-80-1EP_10x10_P0.4mm_EP3.4x3.4mm_ThermalVias,1,RP2350_A4_80QFN,C42415655
U5,SOP-8_3.9x4.9mm_P1.27mm,1,APS6404L-3SQR-SN,C5333729
U6,SOT-23-5,1,TLV62569DBV,C141836
U7,QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm,1,CH334F,C5187527
"Y1, Y2",Crystal_SMD_3225-4Pin_3.2x2.5mm,2,ABM8-272-T3 12MHz,C20625731
1 Designator Footprint Quantity Value LCSC Part #
2 AE1 Walsin_RFANT3216120A5T_3216 1 Chip Antenna C127629
3 C1, C6 0402 2 22uF/10V C3845593
4 C10, C9 0402 2 1.5pF C2980160
5 C11, C14, C15, C2, C20, C25, C26, C27, C28, C3, C32, C33, C34, C35, C36, C37, C38, C39, C4, C40, C42, C8 0402 22 100nF C1525
6 C12, C22, C41 0402 3 10uF C307415
7 C13 0402 1 1uF/6.3V C314234
8 C16, C17 0603 2 22uF C2762594
9 C18, C19, C21, C29 0402 4 4.7uF C318563
10 C23 0402 1 6.8pF C318598
11 C24 0805 1 100uF C6882730
12 C30 0603 1 10uF C1691
13 C31 0603 1 1uF C5199872
14 C5, C7 0402 2 15pF C106997
15 J1 USB_Micro-B_Amphenol_10103594-0001LF_Horizontal 1 USB_B_Mini C428495
16 J2 PinHeader_1x06_P1.00mm_Vertical 1 JST Debug
17 J3 MOLEX_104031-0811 1 SD Drive C585350
18 L1 0402 1 6.8nH C882467
19 L2 0402 1 2.7nH C412269
20 L3 0805 1 3.3u C48888263
21 L4 0603 1 2.2uH/1.05A C337911
22 R1, R17, R18, R19, R2, R27, R28, R29, R3, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R4, R40, R44, R45, R5, R52, R53 0402 26 22R C2906914
23 R10, R11, R12, R13, R14, R20, R26, R7, R8, R9 0402 10 1K C11702
24 R15, R16, R21, R41, R42, R43, R6 0402 7 0R C17168
25 R22, R23, R46, R50, R51, R54, R56, R57, R59, R60 0402 10 10K C60490
26 R24, R25 0402 2 27R C5151586
27 R47, R48 0402 2 47K C25792
28 R49 0402 1 33R C25105
29 R55 0402 1 200K C114763
30 R58 0402 1 44.2K C853281
31 U1 DIP-40_W15.24mm_Extender_NoCourtyard_SmallPad 1 EXTENDER
32 U2 WSON-8-1EP_6x5mm_P1.27mm_EP3.4x4.3mm 1 W25Q128JVPIQ C190862
33 U3 QFN-56-1EP_7x7mm_P0.4mm_EP4x4mm 1 ESP32-S3-PICO-1 N8R8 C7545129
34 U4 RP2350-QFN-80-1EP_10x10_P0.4mm_EP3.4x3.4mm_ThermalVias 1 RP2350_A4_80QFN C42415655
35 U5 SOP-8_3.9x4.9mm_P1.27mm 1 APS6404L-3SQR-SN C5333729
36 U6 SOT-23-5 1 TLV62569DBV C141836
37 U7 QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm 1 CH334F C5187527
38 Y1, Y2 Crystal_SMD_3225-4Pin_3.2x2.5mm 2 ABM8-272-T3 12MHz C20625731

Binary file not shown.

Binary file not shown.

BIN
projects/tzpuPico/tools/MZQD/MZQDTool vendored Executable file

Binary file not shown.

View File

@@ -0,0 +1,366 @@
/* =========================================================================
* MZQDTool — Sharp MZ-700 Quick Disk (QD) image tool
*
* Creates and manages QD disk images for the MZ-700 Quick Disk system.
* Supports format, directory listing, and adding MZF files to QD images.
*
* Original V0.30 (c) 2002 by BKK
* Updated V1.00 (c) 2026 Philip Smart — rewritten with configurable disk
* name, fixed file ordering, correct CMT→QD header conversion,
* and robust error handling.
*
* QD disk image format (61455 bytes):
*
* Disk header:
* [00] [16 16] [A5] [block_count] [CRC: 43 52 43]
*
* Per file (2 blocks each: header + data):
*
* Header block:
* [00] [16 16] [A5] [00] [size_lo=40] [size_hi=00]
* [64 bytes: QDHeaderStr]
* [CRC: 43 52 43]
*
* Data block:
* [00] [16 16] [A5] [05] [size_lo] [size_hi]
* [file data]
* [CRC: 43 52 43]
*
* Usage:
* MZQDTool format [-o disk.qd]
* MZQDTool dir [-o disk.qd]
* MZQDTool add <file.mzf> [-o disk.qd]
* ========================================================================= */
#define VERSION "1.00"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define QDSIZE 61455
#define MAXQDFILETYPES 12
#define DEFAULTQDFILE "MZ700.qd"
#define CMTHDRSIZE 128 /* MZF/CMT file header size */
#define QDHDRSIZE 64 /* QD file header size */
/* MZF/CMT tape file header (128 bytes) */
struct CMTHeaderStr {
uint8_t Attribute; /* File type: 01=OBJ, 02=BTX, etc. */
char Name[17]; /* Filename (CR-terminated, null-padded) */
uint16_t Size; /* Data size (0 = use actual file size) */
uint16_t LoadAddress; /* Load address (DTADR) */
uint16_t ExecAddress; /* Execution address (EXADR) */
char Comment[104]; /* Comment area */
};
/* QD file header (64 bytes, stored in header block) */
struct QDHeaderStr {
uint8_t Attribute; /* File type: 01=OBJ, 02=BTX, etc. */
char Name[17]; /* Filename (CR-terminated, null-padded) */
uint16_t Unknown; /* Reserved (usually 0) */
uint16_t Size; /* Data size in bytes */
uint16_t LoadAddress; /* Load address */
uint16_t ExecAddress; /* Execution address */
char Comment[38]; /* Comment (truncated from CMT's 104) */
};
static const char *QDFileTypes[MAXQDFILETYPES] = {
"???", "OBJ", "BTX", "BSD", "BRD", "RB ",
"???", "LIB", "???", "???", "SYS", "GR "
};
static uint8_t QDArray[QDSIZE];
static char qdFileName[256] = DEFAULTQDFILE;
/* ------- Low-level QD block I/O helpers ------- */
static void write_sync(uint16_t *ptr)
{
QDArray[(*ptr)++] = 0x00; /* BREAK */
QDArray[(*ptr)++] = 0x16; /* SYNC */
QDArray[(*ptr)++] = 0x16; /* SYNC */
QDArray[(*ptr)++] = 0xA5; /* SHARP SYNC */
}
static void write_crc(uint16_t *ptr)
{
QDArray[(*ptr)++] = 'C';
QDArray[(*ptr)++] = 'R';
QDArray[(*ptr)++] = 'C';
}
static int save_qd(void)
{
FILE *f = fopen(qdFileName, "wb");
if (!f) {
fprintf(stderr, "ERROR: Cannot write '%s'\n", qdFileName);
return 0;
}
fwrite(QDArray, QDSIZE, 1, f);
fclose(f);
return 1;
}
static int load_qd(void)
{
FILE *f = fopen(qdFileName, "rb");
if (!f) {
fprintf(stderr, "ERROR: Cannot open '%s'\n", qdFileName);
return 0;
}
fread(QDArray, QDSIZE, 1, f);
fclose(f);
return 1;
}
/* ------- Commands ------- */
/* Format: create an empty QD image with 0 files */
static void QDFormat(void)
{
uint16_t ptr = 0;
printf("Formatting '%s' (%d bytes)\n", qdFileName, QDSIZE);
memset(QDArray, 0x00, QDSIZE);
/* Disk header: sync + block_count(0) + CRC */
write_sync(&ptr);
QDArray[ptr++] = 0x00; /* 0 blocks */
write_crc(&ptr);
if (!save_qd()) exit(1);
puts("Done.");
}
/* Dir: list files on the QD */
static void QDDir(void)
{
uint16_t ptr, blockSize;
uint8_t blocks, i;
if (!load_qd()) exit(1);
/* Disk header: 4 sync bytes + block_count + 3 CRC */
ptr = 4;
blocks = QDArray[ptr++];
ptr += 3; /* skip CRC */
printf("Directory of '%s': %d block(s), %d file(s)\n\n",
qdFileName, blocks, blocks / 2);
for (i = 0; i < blocks; i++) {
if (ptr + 7 >= QDSIZE) {
fprintf(stderr, "WARNING: Truncated QD image at block %d\n", i);
break;
}
ptr += 4; /* sync: 00 16 16 A5 */
uint8_t blockType = QDArray[ptr++];
blockSize = QDArray[ptr] | (QDArray[ptr + 1] << 8);
ptr += 2;
if (blockType == 0x00 && blockSize == QDHDRSIZE) {
/* File header block */
struct QDHeaderStr *hdr = (struct QDHeaderStr *)&QDArray[ptr];
uint8_t ft = hdr->Attribute;
if (ft >= MAXQDFILETYPES) ft = 0;
/* Format name: stop at CR or end of field */
char name[18];
memcpy(name, hdr->Name, 17);
name[17] = '\0';
for (int j = 0; j < 17; j++) {
if (name[j] == '\r' || name[j] == '\0') { name[j] = '\0'; break; }
}
printf(" %-3s %-17s Size=%-6u Load=0x%04X Exec=0x%04X\n",
QDFileTypes[ft], name, hdr->Size,
hdr->LoadAddress, hdr->ExecAddress);
} else if (blockType == 0x05) {
/* Data block — skip silently */
} else {
printf(" [block %d: type=0x%02X size=%u]\n", i, blockType, blockSize);
}
ptr += blockSize;
ptr += 3; /* skip CRC */
}
printf("\n%u bytes free\n", QDSIZE - ptr);
}
/* Add: append an MZF file to the QD image */
static void AddFileToQD(const char *mzfFileName)
{
FILE *mzfFile;
uint16_t ptr, fileDataSize;
uint8_t blocks, i;
uint16_t blockSize;
struct CMTHeaderStr cmtHdr;
if (!load_qd()) exit(1);
/* Read block count and skip to end of existing data */
ptr = 4;
blocks = QDArray[ptr];
ptr = 5 + 3; /* past block_count + CRC */
for (i = 0; i < blocks; i++) {
ptr += 4; /* sync */
ptr++; /* block type */
blockSize = QDArray[ptr] | (QDArray[ptr + 1] << 8);
ptr += 2;
ptr += blockSize;
ptr += 3; /* CRC */
}
/* Open and read MZF file */
mzfFile = fopen(mzfFileName, "rb");
if (!mzfFile) {
fprintf(stderr, "ERROR: Cannot open '%s'\n", mzfFileName);
exit(1);
}
fseek(mzfFile, 0, SEEK_END);
long mzfTotalSize = ftell(mzfFile);
fseek(mzfFile, 0, SEEK_SET);
if (mzfTotalSize < CMTHDRSIZE) {
fprintf(stderr, "ERROR: '%s' is too small for MZF format (%ld bytes)\n",
mzfFileName, mzfTotalSize);
fclose(mzfFile);
exit(1);
}
fread(&cmtHdr, CMTHDRSIZE, 1, mzfFile);
fileDataSize = (uint16_t)(mzfTotalSize - CMTHDRSIZE);
/* Check available space */
uint32_t needed = (4+1+2+QDHDRSIZE+3) + (4+1+2+(uint32_t)fileDataSize+3);
if (ptr + needed > QDSIZE) {
fprintf(stderr, "ERROR: Not enough space (need %u, have %u)\n",
(unsigned)needed, QDSIZE - ptr);
fclose(mzfFile);
exit(1);
}
/* ---- Write header block ---- */
write_sync(&ptr);
QDArray[ptr++] = 0x00; /* block type: file header */
QDArray[ptr++] = QDHDRSIZE; /* size low */
QDArray[ptr++] = 0x00; /* size high */
struct QDHeaderStr *qdHdr = (struct QDHeaderStr *)&QDArray[ptr];
memset(qdHdr, 0, QDHDRSIZE);
/* Convert CMT header to QD header */
qdHdr->Attribute = cmtHdr.Attribute;
if (qdHdr->Attribute == 0x05)
qdHdr->Attribute = 0x02; /* MZF tape type 05 → QD type 02 (BTX) */
memcpy(qdHdr->Name, cmtHdr.Name, 17);
qdHdr->Unknown = 0;
/*
* Size field handling:
* - If MZF Size > 0: use it directly (normal file)
* - If MZF Size == 0: use actual file data size (convention for
* ROM images where Size=0 means "whole file"). The QD header
* MUST have the real size — the QD loader uses it to determine
* how many bytes to read.
*/
if (cmtHdr.Size != 0)
qdHdr->Size = cmtHdr.Size;
else
qdHdr->Size = fileDataSize;
qdHdr->LoadAddress = cmtHdr.LoadAddress;
qdHdr->ExecAddress = cmtHdr.ExecAddress;
memcpy(qdHdr->Comment, cmtHdr.Comment, 38);
ptr += QDHDRSIZE;
write_crc(&ptr);
/* ---- Write data block ---- */
write_sync(&ptr);
QDArray[ptr++] = 0x05; /* block type: file data */
QDArray[ptr++] = fileDataSize & 0xFF;
QDArray[ptr++] = (fileDataSize >> 8) & 0xFF;
fread(&QDArray[ptr], 1, fileDataSize, mzfFile);
ptr += fileDataSize;
write_crc(&ptr);
fclose(mzfFile);
/* Update block count (+2: one header block, one data block) */
QDArray[4] = blocks + 2;
/* Format name for display */
char name[18];
memcpy(name, cmtHdr.Name, 17);
name[17] = '\0';
for (int j = 0; j < 17; j++) {
if (name[j] == '\r' || name[j] == '\0') { name[j] = '\0'; break; }
}
printf(" Added: type=0x%02X name=\"%s\" size=%u load=0x%04X exec=0x%04X\n",
qdHdr->Attribute, name, qdHdr->Size,
qdHdr->LoadAddress, qdHdr->ExecAddress);
printf(" QD: %d blocks, %u bytes free\n", blocks + 2, QDSIZE - ptr);
if (!save_qd()) exit(1);
}
/* ------- Usage and main ------- */
static void usage(void)
{
printf("Usage:\n");
printf(" MZQDTool format [-o disk.qd] Format empty QD image\n");
printf(" MZQDTool dir [-o disk.qd] List QD directory\n");
printf(" MZQDTool add <file.mzf> [-o disk.qd] Add MZF file to QD\n");
printf("\n");
printf("Options:\n");
printf(" -o <filename> QD image file (default: %s)\n", DEFAULTQDFILE);
printf("\n");
}
int main(int argc, char *argv[])
{
printf("\nMZQDTool V%s (c) 2002 BKK, 2026 Philip Smart\n\n", VERSION);
if (argc < 2) {
usage();
return 1;
}
/* Parse -o option from any position */
for (int i = 1; i < argc - 1; i++) {
if (strcmp("-o", argv[i]) == 0) {
strncpy(qdFileName, argv[i + 1], sizeof(qdFileName) - 1);
qdFileName[sizeof(qdFileName) - 1] = '\0';
/* Remove -o and its argument from argv for command parsing */
for (int j = i; j < argc - 2; j++)
argv[j] = argv[j + 2];
argc -= 2;
break;
}
}
if (strcmp("format", argv[1]) == 0) {
QDFormat();
} else if (strcmp("dir", argv[1]) == 0) {
QDDir();
} else if (strcmp("add", argv[1]) == 0) {
if (argc < 3) {
fprintf(stderr, "ERROR: No MZF file specified\n");
return 2;
}
AddFileToQD(argv[2]);
} else {
fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]);
usage();
return 1;
}
return 0;
}

19
projects/tzpuPico/tools/MZQD/Makefile vendored Normal file
View File

@@ -0,0 +1,19 @@
# MZQDTool - Sharp MZ-700 Quick Disk image tool
# (c) 2002 BKK, 2026 Philip Smart
#
# Usage:
# make Build MZQDTool
# make clean Remove build artifacts
CC = gcc
CFLAGS = -Wall -Wno-unused-result -O2
TARGET = MZQDTool
SRC = MZQDTool.c
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $<
clean:
rm -f $(TARGET)
.PHONY: clean

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
projects/tzpuPico/tools/MZQDTool vendored Executable file

Binary file not shown.

View File

@@ -1,385 +0,0 @@
#define VERSION "0.30"
#define FMS 0xEFFF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
#define QDSIZE 61455
#define MAXQDFILETYPES 12
struct CMTHeaderStr
{
unsigned char Attribute;
char Name[17];
unsigned short Size;
unsigned short LoadAddress;
unsigned short ExecAddress;
char Comment[104];
};
struct QDHeaderStr
{
unsigned char Attribute;
char Name[17];
unsigned short Unknown;
unsigned short Size;
unsigned short LoadAddress;
unsigned short ExecAddress;
char Comment[38];
};
char QDFileTypes[MAXQDFILETYPES][4] = {
"???",
"OBJ",
"BTX",
"BSD",
"BRD",
"RB ",
"???",
"LIB",
"???",
"???",
"SYS",
"GR "
};
unsigned char QDArray[QDSIZE];
unsigned short QDPtr;
void QDFormat(void)
{
FILE *QDFile;
unsigned char QDFormatByte;
unsigned short Counter;
puts("Format");
QDPtr = 0;
QDArray[QDPtr++] = 0x00; // BREAK
QDArray[QDPtr++] = 0x16; // SYNC CHAR1
QDArray[QDPtr++] = 0x16; // SYNC CHAR2
QDArray[QDPtr++] = 0xA5; // SHARP SYNC
QDArray[QDPtr++] = 0x00; // 0 data blocks on disk
QDArray[QDPtr++] = 'C'; // CRC
QDArray[QDPtr++] = 'R'; // CRC
QDArray[QDPtr++] = 'C'; //
QDArray[QDPtr++] = 0x00; // BREAK
QDArray[QDPtr++] = 0x16; // SYNC CHAR1
QDArray[QDPtr++] = 0x16; // SYNC CHAR2
QDArray[QDPtr++] = 0xA5;
// 12
QDFormatByte = 0xAA;
Counter = FMS - 65; // FMS 0xEFFF = 61439, 61455 - 61439 = 16
do
{
QDFormatByte = ~QDFormatByte;
QDArray[QDPtr++] = QDFormatByte;
Counter--;
} while(Counter != 0);
QDArray[QDPtr++] = 0x00;
QDArray[QDPtr++] = 'C'; // CRC
QDArray[QDPtr++] = 'R'; // CRC
QDArray[QDPtr++] = 'C'; // CRC
QDArray[QDPtr++] = 0x00;
// *** ADD DIRECTORY TERMINATOR ***
uint32_t termPos = QDSIZE - 64; // Last 64 bytes
memset(&QDArray[termPos], 0, 64);
QDArray[termPos + 0] = 0x00; // BREAK
QDArray[termPos + 1] = 0x16;
QDArray[termPos + 2] = 0x16;
QDArray[termPos + 3] = 0xA5;
QDArray[termPos + 4] = 0x00; // attribute 0 = end of directory
QDArray[termPos + 5] = 0x40; // size low (64)
QDArray[termPos + 6] = 0x00; // size high
// rest zero
if((QDFile = fopen("MZ700.QD", "wb")) != NULL)
{
fwrite(QDArray, QDSIZE, 1, QDFile);
fclose(QDFile);
}
}
unsigned short SeekSync(unsigned short Ptr)
{
unsigned char SyncFound;
SyncFound = FALSE;
do
{
if(QDArray[Ptr++] == 0x16)
{
if(QDArray[Ptr++] == 0x16) SyncFound = TRUE;
else Ptr--;
}
} while(!SyncFound && (Ptr <= QDSIZE));
return(Ptr);
}
void QDDir(void)
{
FILE *QDFile;
unsigned char QDBlocks;
unsigned char Counter;
unsigned char QDFileType;
unsigned short QDBlockSize;
unsigned short PtrSave;
if((QDFile = fopen("MZ700.qd", "rb")) != NULL)
{
fread(QDArray, QDSIZE, 1, QDFile);
fclose(QDFile);
QDPtr = 0;
QDPtr = SeekSync(QDPtr);
QDPtr++;
QDBlocks = QDArray[QDPtr];
puts("DIRECTORY OF QD:");
for(Counter = 0; Counter < QDBlocks; Counter++)
{
QDPtr = SeekSync(QDPtr);
PtrSave = QDPtr;
QDBlockSize = QDArray[QDPtr + 2];
QDBlockSize = QDBlockSize + QDArray[QDPtr + 3] * 256;
// printf("BLSize: %u -> %04X\n", QDBlockSize, QDBlockSize);
QDPtr++;
if(QDArray[QDPtr] == 0x00)
{
QDPtr += 3;
QDFileType = QDArray[QDPtr++];
if(QDFileType >= MAXQDFILETYPES) QDFileType = 0;
printf(" %s \"", QDFileTypes[QDFileType]);
do
{
printf("%c", QDArray[QDPtr++]);
} while(QDArray[QDPtr] != 0x0d);
puts("\"");
}
QDPtr = PtrSave + QDBlockSize;
}
puts("Ready");
}
}
void AddFileToQD(char *MZFileName)
{
FILE *QDFile;
FILE *MZFFile;
unsigned short FilePos;
unsigned short MZFFileSize;
unsigned short QDPtr;
unsigned char QDBlocks;
unsigned short QDBlockSize;
unsigned short Counter;
unsigned short *usPtr;
unsigned char CMTHeader[sizeof(struct CMTHeaderStr)];
struct CMTHeaderStr *CMTHeaderPtr;
struct QDHeaderStr *QDHeaderPtr;
printf("try to add %s\n", MZFileName);
if((QDFile = fopen("MZ700.QD", "rb")) == NULL)
{
puts("file MZ700.QD not found");
exit(3);
}
fread(QDArray, QDSIZE, 1, QDFile);
fclose(QDFile);
QDPtr = 0;
QDPtr = SeekSync(QDPtr);
QDPtr++;
QDBlocks = QDArray[QDPtr++];
QDPtr = QDPtr + 3; // jump over CRC
for(Counter = 0; Counter < QDBlocks; Counter++)
{
QDPtr = SeekSync(QDPtr);
QDPtr = QDPtr + 2; // jump over 0xA5 and the next byte
QDBlockSize = QDArray[QDPtr++];
QDBlockSize = QDBlockSize + QDArray[QDPtr++] * 256;
// printf("BLSize: %u -> %04X\n", QDBlockSize, QDBlockSize);
QDPtr = QDPtr + QDBlockSize;
QDPtr = QDPtr + 3; // jump over CRC
}
if((MZFFile = fopen(MZFileName, "rb")) == NULL)
{
printf("file %s not found\n", MZFileName);
exit(5);
}
fseek(MZFFile, 0, SEEK_END);
MZFFileSize = ftell(MZFFile);
fseek(MZFFile, 0, SEEK_SET);
if(MZFFileSize > (QDSIZE - QDPtr + 14))
{
printf("file %s is to big, only %u bytes free\n", MZFileName, QDSIZE - QDPtr);
}
else
{
QDArray[QDPtr++] = 0x00; // BREAK
QDArray[QDPtr++] = 0x16; // SYNCCHAR1
QDArray[QDPtr++] = 0x16; // SYNCCHAR2
QDArray[QDPtr++] = 0xA5;
QDArray[QDPtr++] = 0x00;
QDArray[QDPtr++] = 64; // headerlength fixed
QDArray[QDPtr++] = 0x00;
/*
fread(&QDArray[QDPtr], 1, 64, MZFFile);
if(QDArray[QDPtr] == 0x05) QDArray[QDPtr] = 2; // BTX file
QDPtr = QDPtr + 64;
fseek(MZFFile, 128, SEEK_SET); // go to end of MZF header
*/
fread(CMTHeader, 1, sizeof(struct CMTHeaderStr), MZFFile);
CMTHeaderPtr = (struct CMTHeaderStr *) &CMTHeader[0];
QDHeaderPtr = (struct QDHeaderStr *) &QDArray[QDPtr];
QDHeaderPtr->Attribute = CMTHeaderPtr->Attribute;
if(CMTHeaderPtr->Size != 0)
{
if(QDHeaderPtr->Attribute == 0x05) QDHeaderPtr->Attribute = 0x02;
}
memcpy(QDHeaderPtr->Name, CMTHeaderPtr->Name, 17);
if(CMTHeaderPtr->Size == 0)
{
memcpy(&QDHeaderPtr->Unknown, &CMTHeaderPtr->Size, 64 - 18);
}
else
{
QDHeaderPtr->Unknown = 0;
QDHeaderPtr->Size = CMTHeaderPtr->Size;
QDHeaderPtr->LoadAddress = CMTHeaderPtr->LoadAddress;
QDHeaderPtr->ExecAddress = CMTHeaderPtr->ExecAddress;
memcpy(QDHeaderPtr->Comment, CMTHeaderPtr->Comment, 38);
}
QDPtr = QDPtr + sizeof(struct QDHeaderStr);
QDArray[QDPtr++] = 'C';
QDArray[QDPtr++] = 'R';
QDArray[QDPtr++] = 'C';
QDArray[QDPtr++] = 0x00; // BREAK
QDArray[QDPtr++] = 0x16; // SYNCCHAR1
QDArray[QDPtr++] = 0x16; // SYNCCHAR2
QDArray[QDPtr++] = 0xA5;
QDArray[QDPtr++] = 0x05;
usPtr = (unsigned short *) &QDArray[QDPtr];
*usPtr = MZFFileSize - 128;
QDPtr = QDPtr + 2;
fread(&QDArray[QDPtr], 1, MZFFileSize - 128, MZFFile);
QDPtr = QDPtr + MZFFileSize - 128;
QDArray[QDPtr++] = 'C';
QDArray[QDPtr++] = 'R';
QDArray[QDPtr++] = 'C';
QDArray[4] = QDArray[4] + 2; // increase blockcounts
}
fclose(MZFFile);
QDFile = fopen("MZ700.QD", "wb");
fwrite(QDArray, QDSIZE, 1, QDFile);
fclose(QDFile);
/*
// *** ADD DIRECTORY TERMINATOR ***
uint32_t termPos = QDSIZE - 64; // Last 64 bytes
memset(&QDArray[termPos], 0, 64);
QDArray[termPos + 0] = 0x00; // BREAK
QDArray[termPos + 1] = 0x16;
QDArray[termPos + 2] = 0x16;
QDArray[termPos + 3] = 0xA5;
QDArray[termPos + 4] = 0x00; // attribute 0 = end of directory
QDArray[termPos + 5] = 0x40; // size low (64)
QDArray[termPos + 6] = 0x00; // size high
// rest zero
*/
}
int main(int argc, char *argv[])
{
printf("\nMZQDTool V %s (c) 2002 by BKK\n\n", VERSION);
if(argc == 1)
{
puts("usage: mzqdtool [format] [dir] [add filename]");
puts("");
exit(1);
}
if(strcmp("format", argv[1]) == 0) QDFormat();
if(strcmp("dir", argv[1]) == 0) QDDir();
if(strcmp("add", argv[1]) == 0)
{
if(argc < 3)
{
puts("error: no file to add");
exit(2);
}
AddFileToQD(argv[2]);
}
return(0);
}