@nataliapc/mcp-openmsx 1.2.11 → 1.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/resources/book--msx-top-secret-3/mts3-appendix-english-upd2.md +25863 -0
  3. package/resources/book--msx-top-secret-3/mts3-complete-english.md +44895 -0
  4. package/resources/programming/asm_develop_a_program_in_cartridge_rom.md +1881 -0
  5. package/resources/programming/toc.json +6 -0
  6. package/resources/system/how_to_detect_ram.md +14 -0
  7. package/resources/system/mrc_wiki_megarom_mappers.md +533 -0
  8. package/resources/system/the_memory.md +118 -0
  9. package/resources/system/toc.json +18 -0
  10. package/vector-db/__manifest/_transactions/0-675ee228-bffb-4636-80e5-cdfde25cc4fe.txn +2 -0
  11. package/vector-db/__manifest/_versions/18446744073709551614.manifest +0 -0
  12. package/vector-db/__manifest/_versions/latest_version_hint.json +1 -0
  13. package/vector-db/msxdocs.lance/_indices/{4d3bd360-e3c6-408d-b0ff-a4d6bd9580cb → 37194b01-2a25-40d1-ac38-7fbe254df5ea}/metadata.lance +0 -0
  14. package/vector-db/msxdocs.lance/_indices/{4d3bd360-e3c6-408d-b0ff-a4d6bd9580cb/part_0_docs.lance → 37194b01-2a25-40d1-ac38-7fbe254df5ea/part_2_docs.lance} +0 -0
  15. package/vector-db/msxdocs.lance/_indices/37194b01-2a25-40d1-ac38-7fbe254df5ea/part_2_invert.lance +0 -0
  16. package/vector-db/msxdocs.lance/_indices/37194b01-2a25-40d1-ac38-7fbe254df5ea/part_2_tokens.lance +0 -0
  17. package/vector-db/msxdocs.lance/_transactions/0-dd155672-40e6-4c6a-942f-7fcbe8c3dbd0.txn +0 -0
  18. package/vector-db/msxdocs.lance/_transactions/1-e7230cbd-ce8e-465c-9b85-b91443862427.txn +0 -0
  19. package/vector-db/msxdocs.lance/_versions/18446744073709551613.manifest +0 -0
  20. package/vector-db/msxdocs.lance/_versions/18446744073709551614.manifest +0 -0
  21. package/vector-db/msxdocs.lance/data/{110001110001011010001000876c134b8296fbc47762d1e1ab.lance → 000100110110001011110001fc578141d296825d0bea11c95d.lance} +0 -0
  22. package/vector-db/msxdocs.lance/_indices/4d3bd360-e3c6-408d-b0ff-a4d6bd9580cb/part_0_invert.lance +0 -0
  23. package/vector-db/msxdocs.lance/_indices/4d3bd360-e3c6-408d-b0ff-a4d6bd9580cb/part_0_tokens.lance +0 -0
  24. package/vector-db/msxdocs.lance/_transactions/0-6f47c9fc-3657-40f0-9dd4-c7226b2a4805.txn +0 -0
  25. package/vector-db/msxdocs.lance/_transactions/1-2bb7426e-a4b0-40ea-9a58-00c4985fc6a9.txn +0 -0
@@ -0,0 +1,1881 @@
1
+ # Develop a program in cartridge ROM
2
+
3
+ This page was last modified 17:37, 16 October 2025 by NYYRIKKI. Based on work by Gdx and S0urceror and others.
4
+
5
+ Source: https://www.msx.org/wiki/Develop_a_program_in_cartridge_ROM
6
+
7
+ # Contents
8
+ * [1 Develop a program in cartridge ROM](#Develop_a_program_in_cartridge_ROM)
9
+ + [1.1 The ROM Header](#The_ROM_Header)
10
+ - [1.1.1 INIT](#INIT)
11
+ - [1.1.2 STATEMENT](#STATEMENT)
12
+ - [1.1.3 DEVICE](#DEVICE)
13
+ - [1.1.4 TEXT](#TEXT)
14
+ + [1.2 Create a ROM without mapper](#Create_a_ROM_without_mapper)
15
+ - [1.2.1 Typical examples to make a 32kB ROM](#Typical_examples_to_make_a_32kB_ROM)
16
+ - [1.2.2 Example to make a 48kB ROM](#Example_to_make_a_48kB_ROM)
17
+ + [1.3 Create a ROM with disks support](#Create_a_ROM_with_disks_support)
18
+ - [1.3.1 Method that uses the hook H.STKE](#Method_that_uses_the_hook_H.STKE)
19
+ - [1.3.2 Method that uses a BASIC program](#Method_that_uses_a_BASIC_program)
20
+ + [1.4 Create a ROM with mapper](#Create_a_ROM_with_mapper)
21
+ - [1.4.1 Examples to make a 128kB ROM for ASCII 16k mapper](#Examples_to_make_a_128kB_ROM_for_ASCII_16k_mapper)
22
+ * [1.4.1.1 Example for Glass assembler](#Example_for_Glass_assembler)
23
+ * [1.4.1.2 Example for Sjasm assembler](#Example_for_Sjasm_assembler)
24
+ * [1.4.1.3 Example for tniASM assembler](#Example_for_tniASM_assembler)
25
+ * [1.4.1.4 Example for Zasm assembler](#Example_for_Zasm_assembler)
26
+ + [1.5 Search for RAM](#Search_for_RAM)
27
+ + [1.6 Allocate RAM (workarea)](#Allocate_RAM_.28workarea.29)
28
+ + [1.7 Useful system Variables](#Useful_system_Variables)
29
+
30
+ # Develop a program in cartridge ROM
31
+
32
+ MSX cartridge ROM can take a multitude of forms depending on the needs. Only the programming aspect will be explained here.
33
+
34
+ A ROM needs a header to be auto-executed by the system when the MSX is initialized.
35
+
36
+ After finding the RAM and initializing the system variables (system variables and work area), the MSX system looks for the ROM headers in all the slots on the memory pages 4000h-7FFFh and 8000h-BFFFh. The search is done in ascending order. When a primary Slot is expanded, the search is done in the corresponding secondary Slots before going to the next Primary Slot.
37
+
38
+ When the system finds a header, it selects the ROM slot only on the memory page corresponding to the address specified in INIT then, runs the program in ROM at the same address by an inter-slot call.
39
+
40
+ ## The ROM Header
41
+
42
+ A header consists of 16 bytes and should be placed at 4000h or 8000h as below.
43
+
44
+ | Header | Name | Use |
45
+ | --- | --- | --- |
46
+ | +0 | ID | Put these first two bytes at 041H and 042H (`AB`) to indicate that it is an additional ROM. |
47
+ | +2 | INIT | Address of the routine to call to initialize a work area or I/O ports, or run a game, etc. The system calls the address from INIT of each ROM header during the MSX initialisation [in that order](/wiki/The_Memory "The Memory"). |
48
+ | +4 | STATEMENT | Runtime address of a program whose purpose is to add instructions to the MSX-Basic using CALL. STATEMENT is called by [CALL](/wiki/CALL "CALL") instructions. It is ignored when 0000h. It is not called at MSX start up. |
49
+ | +6 | DEVICE | Execution address of a program used to control a device built into the cartridge. For example, a disk interface. It is not called at MSX start up. |
50
+ | +8 | TEXT | Pointer of the tokenizen Basic program contained in ROM. TEXT must be always an address more than 8000h and be specified in the header of the page 8000h-BFFFh. **In other cases, it must always be 0000h** under penalty of causing crash or bug. |
51
+ | +10 | Reserved | 6 bytes reserved for future updates. |
52
+
53
+ > **Note:** Unused addresses and reserved bytes have to set to 0000h.
54
+
55
+ ### INIT
56
+
57
+ This is the first address taken into account. When this address is greater than 0000h, the system selects the ROM slot on the memory slot corresponding to the address and executes the program in ROM at the same address.
58
+
59
+ At the time of program execution, the C register contains the slot number of the ROM in the form F000SSPP. The routine must end with a RET. All registers can be modified by routine except SP. In place of an initialization routine, the ROM may very well contain a game.
60
+
61
+ Trick if your ROM has a size of 32K (4000h-BFFFh):
62
+
63
+ 1. When INIT is an address between 4010h-7FFFh, you can select the second part (8000h-BFFFh) by running the routine below at start.
64
+
65
+ ```
66
+ call RSLREG ; Read the primary slots register
67
+ rrca
68
+ rrca
69
+ and 3
70
+ ld c,a
71
+ ld b,0
72
+ ld hl,EXPTBL ; HL = Address of the secondary slot flags table
73
+ add hl,bc
74
+ ld a,(hl)
75
+ and 80h ; Keep the bit 7 (secondary slot flag)
76
+ or c
77
+ ld c,a
78
+ inc hl
79
+ inc hl
80
+ inc hl
81
+ inc hl ; HL = Address of the secondary slot register in the secondary slot register table
82
+ ld a,(hl)
83
+ and 0Ch
84
+ or c
85
+ ld h,080h
86
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
87
+ ```
88
+
89
+ Or this method that is shorter (see note below).
90
+
91
+ ```
92
+ ld a,c
93
+ ld h,080h ; The ENASLT routine does not take into account the register L
94
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
95
+ ```
96
+
97
+ 2. When INIT is an address between 8010h-BFFFh, you can select the first part (4000h-7FFFh) by running the routine below at start.
98
+
99
+ ```
100
+ call RSLREG ; Read the primary slots register
101
+ rrca
102
+ rrca
103
+ rrca
104
+ rrca
105
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
106
+ ld c,a
107
+ ld b,0
108
+ ld hl,EXPTBL ; HL = Address of the secondary slot flags table
109
+ add hl,bc
110
+ ld a,(hl)
111
+ and 80h ; Keep the bit 7 (secondary slot flag)
112
+ or c
113
+ ld c,a
114
+ inc hl
115
+ inc hl
116
+ inc hl
117
+ inc hl ; HL = Address of the secondary slot register in the secondary slot register table
118
+ ld a,(hl)
119
+ and 0Ch
120
+ or c
121
+ ld h,040h ; The ENASLT routine does not take into account the register L
122
+ call ENASLT ; Select the ROM on page 4000h-7FFFh
123
+ ```
124
+
125
+ Or this method that is simpler (see note below).
126
+
127
+ ```
128
+ ld a,c
129
+ ld h,040h ; The ENASLT routine does not take into account the register L
130
+ call ENASLT ; Select the ROM on page 4000h-7FFFh
131
+ ```
132
+
133
+ > **Note:** For both examples, the first method is considered as the most standard. I give the alternative method because I remember seeing it in a old documentation and it seems actually 100% reliable. I tested it on all configurations emulated by blueMSX. Given that I can no longer find this doc to confirm that this register as well as HL can be used, and as it is not documented in the MSX-Data pack, the main technical source today, please use this method only if you are running out of memory in your ROM in the meantime, waiting for a more established confirmation.
134
+
135
+ ### STATEMENT
136
+
137
+ Processing program of the instruction must reside on the page 4000h-7FFFh.
138
+
139
+ An instruction called by [CALL](/wiki/CALL "CALL") must have the following format:
140
+
141
+ `CALL <Instruction name> [(variable[, variable][,...])]`
142
+
143
+ Name of the instruction can be up to 15 characters. When the BASIC interpreter finds the instruction CALL, it copies its name into the PROCNM work area (0FD89h) and then searches the slots in ascending order for a STATEMENT address greater than 0000h to transmit the control for that instruction. At this point, the double register HL contains the address of the parameter that follows the name of the statement in the listing. The instruction can be processed. At the output, HL must indicate the next instruction to be processed and the Carry flag must indicate if there has been an error.
144
+
145
+ Here is an example of a procedure with CALL NAME(0,0) followed by A=0:
146
+
147
+ - The listing therefore contains `CALL NAME (0,0): A=0`.
148
+ HL points to the character "(".
149
+ Carry flag = 1.
150
+ `PROCNM` = "N","A","M","E",00h (00h can be also 3Ah)
151
+ - Processing of the instruction by the routine at the address specified at STATEMENT.
152
+ If the name does not match then leave HL as is and put Carry at 1 before handing over to the interpreter (by a `RET`).
153
+ If name matches, execute the statement routine and its parameters then, point the next statement with HL and set Carry to 0 if there is no error in the parameters.
154
+ - End of treatment.
155
+ HL must point the variable A of A=0.
156
+ Give back to the interpreter (by a `RET`).
157
+
158
+ > **Note:** Avoid giving an already existing name to your instruction because according to the position of the ROM in the slots, it could not be taken into account or even cause an error because of the parameters.
159
+
160
+ ### DEVICE
161
+
162
+ This address must be between 4000h-7FFFh. The system can control up to 4 devices per cartridge. The device name must be 15 characters maximum.
163
+
164
+ The process works as follows:
165
+
166
+ - When the BASIC interpreter tries to discover the device.
167
+ - Register A is set to 0FFh
168
+ - `PROCNM` work area (0FD89h) contains the requested device name.
169
+ For example with `OPEN "NAME:abc.txt"` `PROCNM` contains 'N','A','M','E',0.
170
+ If the code in the cartridge supports the requested device it should respond with device-nr 1 to 4 in A and the carry cleared. If it is not supported the carry should be set. At success the BASIC interpreter allocates an I/O channel buffer for this device.
171
+ - For subsequent I/O operations this address is called again with the operation-id.
172
+ - Register A is set to one of the operation-id's specified below.
173
+ - DEVICE (0FD99h) is set to the device-nr in question.
174
+ Return values depend on the requested operation.
175
+
176
+ Operation ID's:
177
+
178
+ | Reg.A | Operation | Input | Output at success | Output at faillure |
179
+ | --- | --- | --- | --- | --- |
180
+ | 0 | `OPEN`<br/>Called after `OPEN`, `LOAD` or `SAVE`. | Register `HL` = I/O channel pointer.<br/>Register `D` = device code.<br/>Register `E` = file open mode.<br/>`FILNAM` (0F866) contains the requested file name.<br/>`DAC`+2 (0F7F8) contains the # file number. | Results are stored in the buffer pointed to by `HL`.<br/>`HL`[0] = used to store current file open mode, passed in E.<br/>`HL`[1] = identifier to recognise file at subsequent calls, diskrom does `FCB`+0.<br/>`HL`[2] = identifier to recognise file at subsequent calls, diskrom does `FCB`+1.<br/>`HL`[3] = reserved.<br/>`HL`[4] = device code, same as register `D`.<br/>`PTRFIL` (0F864h) set to I/O channel pointer identied by register `HL`. | Call `ERROR` (0406Fh) with error-code set in register `E` |
181
+ | 2 | `CLOSE`<br/>Called after `CLOSE #n`. | Register `HL` = I/O channel pointer.<br/>I/O channel buffer contains all identifying information to the file in question. | File is closed.<br/>`HL`[0] = 0 (closed) | Call `ERROR` (0406Fh) with error-code set in register `E` |
182
+ | 4 | `RANDOM`<br/>Called after `GET #n` or `PUT #n`. | Register `HL` = I/O channel pointer.<br/>Register `DE` = BASIC pointer to character following #n.<br/>Register `B` = 00h is `GET`, 80h is `PUT`. | Record is retrieved or written.<br/>Implement `H.FIEL` handler to know where to read/write.<br/>Implement BASIC instruction parser to know which record.<br/>`HL` = BASIC pointer (updated) | Call `ERROR` (0406Fh) with error-code set in register `E` |
183
+ | 6 | `OUTPUT`<br/>Called after `PRINT #n`. | Register `HL` = I/O channel pointer.<br/>Register `C` = character to output. | Character is saved/output. | Call `ERROR` (0406Fh) with error-code set in register `E` |
184
+ | 8 | `INPUT`<br/>Called after `INPUT #n`. | Register `HL` = I/O channel pointer. | Read or input character.<br/>Register `A` = character.<br/>Carry is cleared. | Carry is set. |
185
+ | 10 | `LOC`<br/>Called after `LOC (n)` | Register `HL` = I/O channel pointer. | File position when sequential read/write or last get/put record number.<br/>- `DAC`+2 and `DAC`+3 = file location<br/>- `VALTYP` (0F663h) = 2 | tbd. |
186
+ | 12 | `LOF`<br/>Called after `LOF (n)` | Register `HL` = I/O channel pointer. | Returns the size of a file on disk in bytes.<br/>- `DAC`+2 and `DAC`+3 = file size<br/> - `VALTYP` (0F663h) = 2 | tbd. |
187
+ | 14 | `EOF`<br/>Called after `EOF(n)`. | Register `HL` = I/O channel pointer. | File position is checked.<br/>Not end-of-file:<br/>- `DAC`+2 and `DAC`+3 = 0<br/>- `VALTYP` (0F663h) = 2<br/>- Carry is cleared.<br/>- Register `A` = 1.<br/>End-of-file:<br/>- `DAC`+2 and `DAC`+3 = 255<br/>- `VALTYP` (0F663h) = 2<br/>- Carry is set.<br/>- Register `A` = 0. | `DAC`+2 and `DAC`+3 = 255<br/>`VALTYP` (0F663h) = 2<br/>Carry is set.<br/>Register `A` = 0. |
188
+ | 16 | `FPOS` | tbd. | tbd. | tbd. |
189
+ | 18 | `BACKUP` | tbd. | tbd. | tbd. |
190
+
191
+ File open modes:
192
+
193
+ | Mode | Description |
194
+ | --- | --- |
195
+ | 0 | `CLOSED` - file is closed |
196
+ | 1 | `INPUT` - file is opened for input |
197
+ | 2 | `OUTPUT` - file is opened for output, overwriting old file if it exists |
198
+ | 4 | `RANDOM` - file is opened for random access |
199
+ | 8 | `APPEND` - file is opened for output, the filepointer is set to the end of the file |
200
+
201
+ ### TEXT
202
+
203
+ This TEXT pointer indicates the beginning of the Basic program to be executed automatically at MSX start. The maximum size of the program is 16 kB, stored between 8000h and BFFFh. The first byte of the program must always be zero. It must be encoded in tokenized format, not ASCII text. The addresses corresponding to the program line numbers are linked to their actual internal corresponding addresses.
204
+
205
+ Method to put a Basic program in ROM:
206
+
207
+ 1. A Basic program starts at 08000h on a 32 kB MSX or more by default. It must be shifted at least to desired address (08012h for this example) to insert the header of the ROM. To do this, enter the following line under Basic:
208
+ `POKE &HF676,&H13: POKE &HF677,&H80: POKE &H8012,0: NEW`
209
+ 2. Load the Basic program to ROM by entering the following instruction.
210
+ `LOAD"Name.BAS"`
211
+ 3. Then save the program by entering the following instruction:
212
+ `SAVE"Name2.BAS"`
213
+ 4. Put the 08012h address to TEXT in the header of the page 8000h-BFFFh, then replace the first byte (FFh) by 00h in the file "Name2.BAS" and copy its content to the ROM at 08012h.
214
+
215
+ Example in assembler:
216
+
217
+ ```
218
+ org 08000h
219
+
220
+ ROMheader:
221
+ db "AB"
222
+ dw 0,0,0,08012h,0,0,0
223
+
224
+ nop
225
+ nop
226
+
227
+ BasicPRG:
228
+ incbin "NAME2.BAS" ; The first byte (FFh) must be previously replaced by 00h
229
+
230
+ ds 4000h - ($ - ROMheader),0
231
+ ```
232
+
233
+ ## Create a ROM without mapper
234
+
235
+ In the chapter "the ROM header" you can see that the ROM header can be placed to 4000h or 8000h, or even both. In addition, your program can start from almost any address since the system is making an inter-slot call to the address specified by INIT. The only constraints are the header and interrupts. Indeed, the system interrupt routine is at address 0038h. If you put 03000h to INIT, your ROM will need to have a replacement interrupt routine since it will be selected on page 0000h-3FFFh to be executed. The problem also occurs on page C000h-FFFFh because of Hooks and system variables. You need have a high mastery of system and hardware to choose these pages. Better to choose an address between 4000h and BFFFh and if necessary, use the other two pages to put data (text and graphics for example).
236
+
237
+ The size of a ROM without mapping can vary in theory from 1kB to 64kB. In practice, it is difficult to find ROMs of less than 16kB.
238
+
239
+ If the ROM is 48kB, the C000h-FFFFh page will contain undefined values ​​(usually 0FFh).
240
+
241
+ If the ROM is 32kB or less, depending on the hardware connections the unused parts will contain undefined values ​​or mirrors as shown below.
242
+
243
+ ```
244
+ 8kB ROM
245
+ --------------------------------------------
246
+ Slot
247
+ +--------+
248
+ Page C000h~FFFFh | Mirror |
249
+ +--------+
250
+ Page 8000h~BFFFh | Mirror | +------------+
251
+ +--------+ / | 8kB Mirror |
252
+ Page 4000h~7FFFh | ROM | +- - - - - - +
253
+ +--------+ \ | 8kB ROM |
254
+ Page 0000h~3FFFh | Mirror | +------------+
255
+ +--------+
256
+
257
+ 16kB ROM
258
+ --------------------------------------------
259
+ Slot Slot
260
+ +--------+ +--------+
261
+ Page C000h~FFFFh | Mirror | | Mirror |
262
+ +--------+ +--------+
263
+ Page 8000h~BFFFh | Mirror | | ROM |
264
+ +--------+ or +--------+
265
+ Page 4000h~7FFFh | ROM | | Mirror |
266
+ +--------+ +--------+
267
+ Page 0000h~3FFFh | Mirror | | Mirror |
268
+ +--------+ +--------+
269
+
270
+ 32kB ROM
271
+ --------------------------------------------
272
+ Slot Slot
273
+ +---------+ +--------+
274
+ Page C000h~FFFFh | Mirror2 | | |
275
+ +---------+ + Mirror +
276
+ Page 8000h~BFFFh | | | |
277
+ + ROM + or +--------+
278
+ Page 4000h~7FFFh | | | |
279
+ +---------+ + ROM +
280
+ Page 0000h~3FFFh | Mirror1 | | |
281
+ +---------+ +--------+
282
+
283
+ Mirror1: Mirror of first 16kB of ROM (4000h-7FFFh)
284
+ Mirror2: Mirror of second 16kB of ROM (8000h-BFFFh
285
+ ```
286
+
287
+ You can use these mirrors to confuse people looking to disassemble your program. MegaROMs can have the same mirrors as a 32kb ROM since they are often connected the same way with an additional mapper. Also note that I once saw a MegaROM whose mapper is controlled by an EPM with the mirrors reversed.
288
+
289
+ When a Rom is executed at the INIT address on page 4000h-7FFFh by the system, the CPU can see the half of the Main-ROM on the page 0000h-3FFFh and the available Main-RAM on the other pages.
290
+
291
+ ```
292
+ Areas visible by the CPU
293
+ --------------------------------------------
294
+
295
+ 32-64kB MSX 16kB MSX 8kB MSX
296
+ +---------+ +---------+ +---RAM---+
297
+ Page C000h~FFFFh | RAM | | RAM | |- - - - -|
298
+ +---------+ +---------+ +---------+
299
+ Page 8000h~BFFFh | RAM | | | | |
300
+ +---------+ +---------+ +---------+
301
+ Page 4000h~7FFFh | ROM | | ROM | | ROM |
302
+ +---------+ +---------+ +---------+
303
+ Page 0000h~3FFFh |Main ROM | |Main ROM | |Main ROM |
304
+ +---------+ +---------+ +---------+
305
+ ```
306
+
307
+ When a Rom is executed on page 8000h-CFFFh, the CPU can see the Main-ROM on the pages 0000h-3FFFh and 4000h-7FFFh, and the available Main-RAM on the top page.
308
+
309
+ ```
310
+ Areas visible by the CPU
311
+ --------------------------------------------
312
+
313
+ 32-64kB MSX 16kB MSX 8kB MSX
314
+ +---------+ +---------+ +---RAM---+
315
+ Page C000h~FFFFh | RAM | | RAM | |- - - - -|
316
+ +---------+ +---------+ +---------+
317
+ Page 8000h~BFFFh | ROM | | ROM | | ROM |
318
+ +---------+ +---------+ +---------+
319
+ Page 4000h~7FFFh |Main ROM | |Main ROM | |Main ROM |
320
+ +---------+ +---------+ +---------+
321
+ Page 0000h~3FFFh |Main ROM | |Main ROM | |Main ROM |
322
+ +---------+ +---------+ +---------+
323
+ ```
324
+
325
+ Bottom of the RAM that the CPU can see is indicated by BOTTOM (0FC48h) system variable.
326
+
327
+ ### Typical examples to make a 32kB ROM
328
+
329
+ Below is an example for a ROM that start from page 4000h-7FFFh.
330
+
331
+ ```
332
+ LF: equ 0Ah
333
+ CR: equ 0Dh
334
+
335
+ CHPUT: equ 00A2h ; Address of character output routine of BIOS
336
+ ENASLT: equ 0024h
337
+ INIT32: equ 006Fh
338
+ RSLREG: equ 0138h
339
+
340
+ PageSize: equ 4000h ; 16kB
341
+
342
+ LINL32: equ 0F3AFh
343
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
344
+
345
+ org 4000h
346
+
347
+ ; ### ROM header ###
348
+
349
+ db "AB" ; ID for auto-executable ROM
350
+ dw INIT ; Main program execution address.
351
+ dw 0 ; STATEMENT
352
+ dw 0 ; DEVICE
353
+ dw 0 ; TEXT
354
+ dw 0,0,0 ; Reserved
355
+
356
+ INIT: ; Program code entry point label
357
+
358
+ ld a,32
359
+ ld (LINL32),a ; 32 columns
360
+ call INIT32 ; SCREEN 1
361
+
362
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7BFFFh
363
+
364
+ call RSLREG
365
+ rrca
366
+ rrca
367
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
368
+ ld c,a
369
+ ld b,0
370
+ ld hl,EXPTBL
371
+ add hl,bc
372
+ ld a,(hl)
373
+ and 80h
374
+ or c
375
+ ld c,a
376
+ inc hl
377
+ inc hl
378
+ inc hl
379
+ inc hl
380
+ ld a,(hl)
381
+ and 0Ch
382
+ or c
383
+ ld h,080h
384
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
385
+
386
+ ld hl,Page4000hTXT ; Text pointer into HL
387
+ call Print ; Call the routine Print below
388
+
389
+ jp 08000h ; Jump to above page.
390
+
391
+ Print:
392
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
393
+ and a ; Same as CP 0 but faster.
394
+ ret z ; Back behind the call print if A = 0
395
+ call CHPUT ; Call the routine to display a character.
396
+ inc hl ; Increment the HL value.
397
+ jr Print ; Relative jump to the address in the label Print.
398
+
399
+ ; Message data
400
+ Page4000hTXT: ; Text pointer label
401
+ db "Text from page 4000h-7FFFh",LF,CR,0 ; Zero indicates the end of text
402
+
403
+ ; Padding with 255 to make a fixed page of 16K size
404
+ ; (Alternatively, include macros.asm and use ALIGN 4000H)
405
+
406
+ ds PageSize - ($ - 4000h),255 ; Fill the unused aera in page with 0FFh
407
+
408
+ ; Begin of page 8000h-BFFFh
409
+
410
+ ld hl,Page8000hTXT ; Text pointer
411
+ call Print ; Call the routine Print
412
+
413
+ Finished:
414
+ jr Finished ; Jump to itself endlessly.
415
+
416
+ Page8000hTXT: ; Text pointer label
417
+ db "Text from page 8000h-BFFFh",0 ; Zero indicates the end of text.
418
+
419
+ ds PageSize - ($ - 8000h),255 ; Fill the unused aera with 0FFh
420
+ ```
421
+
422
+ > **Note:** "**ds PageSize - (\$ - 4000h),255**" is here just for the example. You can remove it and replace "**ds PageSize - (\$ - 8000h),255**" at end by "**ds PageSize - ($ - 4000h),255**" to make your own ROM.
423
+
424
+ Below is an example for a ROM that start from page 8000h-BFFFh.
425
+
426
+ ```
427
+ LF: equ 0Ah
428
+ CR: equ 0Dh
429
+
430
+ CHPUT: equ 00A2h ; Address of character output routine of BIOS
431
+ ENASLT: equ 0024h
432
+ INIT32: equ 006Fh
433
+ RSLREG: equ 0138h
434
+
435
+ PageSize: equ 4000h ; 16kB
436
+
437
+ LINL32: equ 0F3AFh
438
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
439
+
440
+ org 4000h
441
+
442
+ ld hl,Page4000hTXT ; Text pointer into HL
443
+ call Print ; Call the routine Print
444
+
445
+ Finished:
446
+ jr Finished ; Jump to itself endlessly.
447
+
448
+ ; Message data
449
+ Page4000hTXT: ; Text pointer label
450
+ db "Text from page 4000h-7FFFh",0 ; Zero indicates the end of text
451
+
452
+ ; Padding with 255 to make a fixed page of 16K size
453
+ ; (Alternatively, include macros.asm and use ALIGN 4000H)
454
+
455
+ ds PageSize - ($ - 4000h),255 ; Fill the unused aera in page with 0FFh
456
+
457
+ ; Begin of page 8000h-BFFFh
458
+
459
+ ; ### ROM header ###
460
+
461
+ db "AB" ; ID for auto-executable ROM
462
+ dw INIT ; Main program execution address.
463
+ dw 0 ; STATEMENT
464
+ dw 0 ; DEVICE
465
+ dw 0 ; TEXT
466
+ dw 0,0,0 ; Reserved
467
+
468
+ INIT: ; Program code entry point label
469
+
470
+ ld a,32
471
+ ld (LINL32),a ; 32 columns
472
+ call INIT32 ; SCREEN 1
473
+
474
+ ; Typical routine to select the ROM on page 4000h-7FFFh from page 8000h-BFFFh
475
+
476
+ call RSLREG
477
+ rrca
478
+ rrca
479
+ rrca
480
+ rrca
481
+ and 3 ;Keep bits corresponding to the page 8000h-BFFFh
482
+ ld c,a
483
+ ld b,0
484
+ ld hl,EXPTBL
485
+ add hl,bc
486
+ ld a,(hl)
487
+ and 80h
488
+ or c
489
+ ld c,a
490
+ inc hl
491
+ inc hl
492
+ inc hl
493
+ inc hl
494
+ ld a,(hl)
495
+ and 0Ch
496
+ or c
497
+ ld h,040h
498
+ call ENASLT ; Select the ROM on page 4000h-7FFFh
499
+
500
+ ld hl,Page8000hTXT ; Text pointer
501
+ call Print ; Call the routine Print below
502
+
503
+ jp 04000h ; Jump to below page.
504
+
505
+ Print:
506
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
507
+ and a ; Same as CP 0 but faster.
508
+ ret z ; Back behind the call print if A = 0
509
+ call CHPUT ; Call the routine to display a character.
510
+ inc hl ; Increment the HL value.
511
+ jr Print ; Relative jump to the address in the label Print.
512
+
513
+ Page8000hTXT: ; Text pointer label
514
+ db "Text from page 8000h-BFFFh",LF,CR,0 ; Zero indicates the end of text.
515
+
516
+ ds PageSize - ($ - 8000h),255 ; Fill the unused aera with 0FFh
517
+ ```
518
+
519
+ ### Example to make a 48kB ROM
520
+
521
+ Below is an example for a 48kB ROM that start from page 4000h-7FFFh. In this example, interrupts are disabled during page 0000h-3FFFh is selected, and since BIOS routines are absent the text is displayed by making direct access to the VDP. You will also find a routine to put back the BIOS. Better to add an interrupt routine if page 0 needs to be selected longer.
522
+
523
+ ```
524
+ LF: equ 0Ah
525
+ CR: equ 0Dh
526
+
527
+ CHPUT: equ 00A2h ; Address of character output routine of BIOS
528
+ ENASLT: equ 0024h
529
+ INIT32: equ 006Fh
530
+ RSLREG: equ 0138h
531
+ SETWRT: equ 0053h ; set address to write in VRAM
532
+
533
+ PageSize: equ 4000h ; 16kB
534
+
535
+ LINL32: equ 0F3AFh
536
+ T32NAM: equ 0F3BDh
537
+ CSRX: equ 0F3DDh
538
+ CSRY: equ 0F3DCh
539
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
540
+
541
+ org 0000h
542
+
543
+ ld hl,Page0000hTXT ; Text pointer into HL
544
+ call PrintP0 ; Call the routine Print for page 0
545
+ ret
546
+
547
+ PrintP0:
548
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
549
+ cp LF
550
+ jr z,Code_LF
551
+ cp CR
552
+ jr z,Code_CR
553
+ and a ; Same as CP 0 but faster.
554
+ ret z ; Back behind the call print if A = 0
555
+ out (098h),a ; Call the routine to display a character.
556
+ inc hl ; Increment the HL value.
557
+ push hl
558
+ ld hl,CSRX
559
+ inc (hl)
560
+ pop hl
561
+ jr PrintP0 ; Relative jump to the address in the label Print.
562
+
563
+ Code_CR:
564
+ push af
565
+ ld a,1
566
+ ld (CSRX),a
567
+ pop af
568
+ inc hl ; Increment the HL value.
569
+ jr PrintP0
570
+ Code_LF:
571
+ push hl
572
+ ld hl,CSRY
573
+ inc (hl)
574
+ pop hl
575
+ inc hl ; Increment the HL value.
576
+ jr PrintP0
577
+
578
+ ; Message data
579
+ Page0000hTXT: ; Text pointer label
580
+ db "Text from page 0000h-3FFFh",LF,CR,0 ; Zero indicates the end of text
581
+
582
+ ds PageSize - $,255 ; Fill the unused aera with 0FFh
583
+
584
+ ;--------------------------
585
+ ; Begin of page 4000h-3FFFh
586
+ ;--------------------------
587
+
588
+ ; ### ROM header ###
589
+
590
+ db "AB" ; ID for auto-executable ROM
591
+ dw INIT ; Main program execution address.
592
+ dw 0 ; STATEMENT
593
+ dw 0 ; DEVICE
594
+ dw 0 ; TEXT (Unused on this page)
595
+ dw 0,0,0 ; Reserved
596
+
597
+ INIT: ; Program code entry point label
598
+
599
+ ld a,32
600
+ ld (LINL32),a ; 32 columns
601
+ call INIT32 ; SCREEN 1
602
+ ld hl,(T32NAM)
603
+ call SETWRT ; Set the VRAM address to write the texte
604
+
605
+ ; Routine to select the ROM on page 0000h-3FFFh (from page 4000h-7FFFh)
606
+
607
+ ld a,(0FFFFh)
608
+ cpl ; reverse all bits
609
+ ld d,a ; Store the current secondary slots register
610
+
611
+ in a,(0A8h)
612
+ ld e,a ; Store the current primary slots register
613
+
614
+ and 03Ch ; 00xxxx00
615
+ ld b,a
616
+ ld a,e
617
+ and 0Ch ; 0000xx00
618
+ rrca
619
+ rrca ; 000000xx
620
+ ld c,a
621
+ rrca
622
+ rrca ; xx000000
623
+ or c ; xx0000xx
624
+ or b
625
+ di
626
+ out (0A8h),a ; Select the primary slot of ROM on page 0000h-3FFFh and C000h-FFFFh
627
+
628
+ ld a,(0FFFFh)
629
+ ld b,a
630
+ cpl
631
+ ld (0FFFFh),a
632
+ ld a,(0FFFFh)
633
+ cp b
634
+ jr nz,NO_SS ; Jump if primary slot
635
+
636
+ cpl
637
+ and 0FCh ; xxxxxx00
638
+ ld b,a
639
+ ld a,(0FFFFh)
640
+ cpl
641
+ and 0Ch ; 0000xx00
642
+ rrca
643
+ rrca ; 000000xx
644
+ or b
645
+ ld (0FFFFh),a ; ROM Selection (Secondary Slot)
646
+ NO_SS:
647
+
648
+ ; Routine to re-select the Main-RAM on page C000h-7FFFh
649
+
650
+ ld a,e
651
+ and 0C0h ; xx000000
652
+ ld b,a
653
+ in a,(0A8h)
654
+ and 03Fh ; 00xxxxxx
655
+ or b
656
+ out (0A8h),a ; Select the prim slot of Main-RAM on page C000h-FFFFh
657
+
658
+ ld a,(0FFFFh)
659
+ cpl
660
+ and 03Fh ; 00xxxxxx
661
+ ld b,a
662
+ ld a,d
663
+ and 0C0h ; xx000000
664
+ or b
665
+ ld (0FFFFh),a ; Select the secondary of Main-RAM slot register
666
+
667
+ call 0000h
668
+
669
+ ; Routine to re-select the Main-ROM on page 0000h-3FFFh
670
+
671
+ ld a,e
672
+ out (0A8h),a ; Restore the register as at start
673
+
674
+ ld a,d
675
+ ld (0FFFFh),a ; Restore the register as at start
676
+ NO_SS2:
677
+ ei
678
+
679
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7FFFh
680
+
681
+ call RSLREG
682
+ rrca
683
+ rrca
684
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
685
+ ld c,a
686
+ ld b,0
687
+ ld hl,EXPTBL
688
+ add hl,bc
689
+ ld a,(hl)
690
+ and 80h
691
+ or c
692
+ ld c,a
693
+ inc hl
694
+ inc hl
695
+ inc hl
696
+ inc hl
697
+ ld a,(hl)
698
+ and 0Ch
699
+ or c
700
+ ld h,080h
701
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
702
+
703
+ ld hl,Page4000hTXT ; Text pointer into HL
704
+ call Print ; Call the routine Print below
705
+
706
+ jp 08000h ; Jump to above page.
707
+
708
+ Print:
709
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
710
+ and a ; Same as CP 0 but faster.
711
+ ret z ; Back behind the call print if A = 0
712
+ call CHPUT ; Call the routine to display a character.
713
+ inc hl ; Increment the HL value.
714
+ jr Print ; Relative jump to the address in the label Print.
715
+
716
+ ; Message data
717
+
718
+ Page4000hTXT: ; Text pointer label
719
+
720
+ db "Text from page 4000h-7FFFh",LF,CR,0 ; Zero indicates the end of text
721
+
722
+ ; Padding with 255 to make a fixed page of 16K size
723
+ ; (Alternatively, include macros.asm and use ALIGN 4000H)
724
+
725
+ ds PageSize - ($ - 4000h),255 ; Fill the unused area in page with 0FFh
726
+
727
+ ;--------------------------
728
+ ; Begin of page 8000h-BFFFh
729
+ ;--------------------------
730
+
731
+ ld hl,Page8000hTXT ; Text pointer
732
+ call Print ; Call the routine Print
733
+
734
+ Finished:
735
+ jr Finished ; Jump to itself endlessly.
736
+
737
+ Page8000hTXT: ; Text pointer label
738
+ db "Text from page 8000h-BFFFh",0 ; Zero indicates the end of text.
739
+
740
+ ds PageSize - ($ - 8000h),255 ; Fill the unused aera with 0FFh
741
+ ```
742
+
743
+ ## Create a ROM with disks support
744
+
745
+ There are two methods to create a ROM with disks support. The first uses the hook `H.STKE` and the second is to launch the ROM from a little BASIC program in ROM.
746
+
747
+ ### Method that uses the hook H.STKE
748
+
749
+ `H.STKE` (0FEDAh) is called after searching in each slot the executable ROMs when initializing the MSX, just before the system starts the Basic environment. This Hook can therefore allow you to automatically run your ROM with the installed disks. If you need to access hard disks, directories or other DOS2 features with kernel 2.31 or later, you also have to put a custom value to `USRTAB` (0F39Ah) during the INIT-routine othervice only DOS1 functions will be available. In earlier kernel versions DOS2 calls are available as long as DOS2 cartridge is present. Please note that populating `H.STKE` always prevents automatically booting disk software from starting even if the hooked routine quits.
750
+
751
+ This example below saves 16 bytes (C500h-C500Fh) in the file "DATA.DAT" on the current disk. In addition of the errors indicated at the BDOS call output (Software errors), the error to know if floppy disk is inserted in current drive or not is also handled but if you need to know more about hardware errors handling see [this site](http://map.grauw.nl/articles/dos-error-handling.php).
752
+
753
+ ```
754
+ LF: equ 0Ah
755
+ CR: equ 0Dh
756
+
757
+ INIT32: equ 006Fh
758
+ CHPUT: equ 00A2h ; Address of character output routine from Main-Rom BIOS
759
+
760
+ RomSize: equ 4000h ; 16kB
761
+ FCBinRAM: equ 0C000h
762
+
763
+ ERRADR: equ 0F323h
764
+ FCBBASE: equ 0F353h
765
+ LINL32: equ 0F3AFh
766
+ BDOS: equ 0F37Dh
767
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
768
+ H_STKE: equ 0FEDAh
769
+ H_PHYD: equ 0FFA7h
770
+ NEWKEY: equ 0FBE5h
771
+
772
+ org 8000h ; Your disk errors handling routine can not be on the page 4000h-7FFFh
773
+
774
+ ; ### ROM header ### (Put 0000h as address when unused)
775
+
776
+ db "AB" ; ID for auto-executable ROM
777
+ dw INIT ; Main program execution address.
778
+ dw 0 ; STATEMENT
779
+ dw 0 ; DEVICE
780
+ dw 0 ; TEXT (Unused on this page)
781
+ dw 0,0,0 ; Reserved
782
+
783
+ ; Setup the hook H.STKE to run the ROM with disk support
784
+
785
+ INIT: ; Program entry point label
786
+
787
+ ld a,c ; Get the ROM slot number
788
+
789
+ ld hl,NewH_STKE
790
+ ld de,H_STKE
791
+ ld bc,4
792
+ ldir ; Copy the routine to execute the ROM to the hook
793
+
794
+ ld (H_STKE+1),a ; Put the ROM slot number to the hook
795
+
796
+ ret ; Back to slots scanning
797
+
798
+ ; Routine to execute the ROM
799
+
800
+ NewH_STKE:
801
+ rst 030h ; Inter-slot call
802
+ db 1 ; This byte will be replaced by the slot number of ROM
803
+ dw ROM_Exe ; Address to execute the ROM
804
+
805
+ ; Start of your program in ROM
806
+
807
+ ROM_Exe:
808
+ ld a,0C9h
809
+ ld (H_STKE),a ; Remove the hook
810
+
811
+ ld hl,(ERR_Routine)
812
+ ld (ERRADR),hl ; Catches the Error routine
813
+
814
+ ld a,32
815
+ ld (LINL32),a ; 32 columns
816
+ call INIT32 ; SCREEN 1
817
+
818
+ ld a,(H_PHYD)
819
+ cp 0C9h ;
820
+ jr nz,DSK_Found ; Jump if disk installed
821
+
822
+ ld hl,NoDisk_TXT ; Text pointer into HL
823
+ call Print ; Call the routine Print below
824
+
825
+ jr NeverEndLoop
826
+
827
+ DSK_Found:
828
+ ld hl,Save_TXT ; Text pointer into HL
829
+ call Print ; Call the routine Print below
830
+
831
+ ld hl,InsDisk
832
+ ld (0F1E6h),hl ; Set address to jump to insert disk routine
833
+
834
+ ld hl,FCBinRAM
835
+ ld (FCBBASE),hl ; Set FCB pointer to 0C000h
836
+ ex hl,de
837
+ ld hl,FCB
838
+ ld bc,128
839
+ ldir ; Initialises the FCB data
840
+
841
+ ld c,1Ah
842
+ ld de,0C500h ; pointer to data to save
843
+ call BDOS
844
+ Write:
845
+ ld c,016h ; Create file
846
+ ld de,FCBinRAM
847
+ call BDOS_WE
848
+ or a
849
+ jp nz,ERROR
850
+
851
+ ld hl,1
852
+ ld (FCBinRAM+14),hl ; Record size = 1 byte
853
+
854
+ ld c,026h ; Write file
855
+ ld de,FCBinRAM
856
+ ld hl,10h
857
+ call BDOS_WE ; Save 16 bytes (0C500h-0C50Fh)
858
+ or a
859
+ jp nz,ERROR
860
+
861
+ ld c,010h ; Close file
862
+ ld de,FCBinRAM
863
+ call BDOS_WE
864
+ or a
865
+ jp nz,ERROR
866
+
867
+ ld hl,SaveOK_TXT ; Text pointer into HL
868
+ jr SaveMES
869
+ ERROR:
870
+ ld hl,SaveERR_TXT
871
+ SaveMES:
872
+ call Print ; Call the routine Print below
873
+
874
+ NeverEndLoop:
875
+ jr NeverEndLoop
876
+
877
+ ; Your
878
+
879
+ InsDisk:
880
+ ld sp,(0D000h) ; Restore SP register
881
+
882
+ ld a,c ; Get error flags
883
+ and 2
884
+ jp z,ERROR ; Jump if disk is present in drive
885
+
886
+ ld hl,InsDisk_TXT
887
+ call Print ; Call the routine Print below
888
+
889
+ RET_KEY:
890
+ ld a,(NEWKEY+7)
891
+ bit 7,a
892
+ jr nz,RET_KEY
893
+
894
+ jp Write
895
+
896
+ ; Print the text pointed by HL
897
+
898
+ Print:
899
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
900
+ and a ; Same as CP 0 but faster.
901
+ ret z ; Back behind the call print if A = 0
902
+ call CHPUT ; Call the routine to display a character.
903
+ inc hl ; Increment the HL value.
904
+ jr Print ; Relative jump to the address in the label Print.
905
+
906
+ BDOS_WE:
907
+ ld (0D000h),sp ; Store SP register
908
+ jp BDOS
909
+
910
+ ; Data
911
+
912
+ NoDisk_TXT: ; Text pointer label
913
+ db "No disk installed!",LF,CR
914
+ db "Turn off the MSX.",0 ; Zero indicates the end of text
915
+ Save_TXT:
916
+ db "Saving",022h,"DATA.DAT",022h,"...",LF,CR,0
917
+ SaveOK_TXT:
918
+ db "File saved",LF,CR,0
919
+ SaveERR_TXT:
920
+ db "File error!!!",LF,CR,0
921
+ InsDisk_TXT:
922
+ db "Insert the floppy disk",LF,CR
923
+ db "then press RETURN",LF,CR,0
924
+
925
+ ERR_Routine:
926
+ dw InsDisk
927
+
928
+ FCB:
929
+ db 0,"DATA DAT"
930
+ ds 116,0 ; Fill the rest of FCB with 00h
931
+
932
+ ds RomSize - ($ & (RomSize-1)),255 ; Fill the unused aera in page with 0FFh
933
+ ```
934
+
935
+ ### Method that uses a BASIC program
936
+
937
+ Following example use the program "10 DEFUSR=&H8024:?USR(0)" to execute the machine program of the ROM. Aside from this difference, it does the same thing as the previous program.
938
+
939
+ ```
940
+ LF: equ 0Ah
941
+ CR: equ 0Dh
942
+
943
+ INIT32: equ 006Fh
944
+ CHPUT: equ 00A2h ; Address of character output routine from Main-Rom BIOS
945
+
946
+ RomSize: equ 4000h ; 16kB
947
+ FCBinRAM: equ 0C000h
948
+
949
+ ERRADR: equ 0F323h
950
+ FCBBASE: equ 0F353h
951
+ LINL32: equ 0F3AFh
952
+ BDOS: equ 0F37Dh
953
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
954
+ H_PHYD: equ 0FFA7h
955
+ NEWKEY: equ 0FBE5h
956
+
957
+ org 8000h ; Your disk errors handling routine can not be on the page 4000h-7FFFh
958
+
959
+ ; ### ROM header ### (Put 0000h as address when unused)
960
+
961
+ db "AB" ; ID for auto-executable ROM
962
+ dw 0 ; INIT
963
+ dw 0 ; STATEMENT
964
+ dw 0 ; DEVICE
965
+ dw 08010h ; TEXT
966
+ dw 0,0,0 ; Reserved
967
+
968
+ INIT: ; Program entry point label
969
+
970
+ ; BASIC Program Data for "10 DEFUSR=&H8024:?USR(0)"
971
+
972
+ db 0,22h,80h,0Ah,0,97h,0DDh,0EFh,0Ch,24h,80h,3Ah,91h,0DDh,28h,11h,29h,0,0,0
973
+
974
+ ; Start of your program in ROM (08024h)
975
+
976
+ ROM_Exe:
977
+
978
+ ld hl,(ERR_Routine)
979
+ ld (ERRADR),hl ; Catches the Error routine
980
+
981
+ ld a,32
982
+ ld (LINL32),a ; 32 columns
983
+ call INIT32 ; SCREEN 1
984
+
985
+ ld a,(H_PHYD)
986
+ cp 0C9h ;
987
+ jr nz,DSK_Found ; Jump if disk installed
988
+
989
+ ld hl,NoDisk_TXT ; Text pointer into HL
990
+ call Print ; Call the routine Print below
991
+
992
+ jr NeverEndLoop
993
+
994
+ DSK_Found:
995
+ ld hl,Save_TXT ; Text pointer into HL
996
+ call Print ; Call the routine Print below
997
+
998
+ ld hl,InsDisk
999
+ ld (0F1E6h),hl ; Set address to jump to insert disk routine
1000
+
1001
+ ld hl,FCBinRAM
1002
+ ld (FCBBASE),hl ; Set FCB pointer to 0C000h
1003
+ ex hl,de
1004
+ ld hl,FCB
1005
+ ld bc,128
1006
+ ldir ; Initialises the FCB data
1007
+
1008
+ ld c,1Ah
1009
+ ld de,0C500h ; pointer to data to save
1010
+ call BDOS
1011
+ Write:
1012
+ ld c,016h ; Create file
1013
+ ld de,FCBinRAM
1014
+ call BDOS_WE
1015
+ or a
1016
+ jp nz,ERROR
1017
+
1018
+ ld hl,1
1019
+ ld (FCBinRAM+14),hl ; Record size = 1 byte
1020
+
1021
+ ld c,026h ; Write file
1022
+ ld de,FCBinRAM
1023
+ ld hl,10h
1024
+ call BDOS_WE ; Save 16 bytes (0C500h-0C50Fh)
1025
+ or a
1026
+ jp nz,ERROR
1027
+
1028
+ ld c,010h ; Close file
1029
+ ld de,FCBinRAM
1030
+ call BDOS_WE
1031
+ or a
1032
+ jp nz,ERROR
1033
+
1034
+ ld hl,SaveOK_TXT ; Text pointer into HL
1035
+ jr SaveMES
1036
+ ERROR:
1037
+ ld hl,SaveERR_TXT
1038
+ SaveMES:
1039
+ call Print ; Call the routine Print below
1040
+
1041
+ NeverEndLoop:
1042
+ jr NeverEndLoop
1043
+
1044
+ ; Your
1045
+
1046
+ InsDisk:
1047
+ ld sp,(0D000h) ; Restore SP register
1048
+
1049
+ ld a,c ; Get error flags
1050
+ and 2
1051
+ jp z,ERROR ; Jump if disk is present in drive
1052
+
1053
+ ld hl,InsDisk_TXT
1054
+ call Print ; Call the routine Print below
1055
+
1056
+ RET_KEY:
1057
+ ld a,(NEWKEY+7)
1058
+ bit 7,a
1059
+ jr nz,RET_KEY
1060
+
1061
+ jp Write
1062
+
1063
+ ; Print the text pointed by HL
1064
+
1065
+ Print:
1066
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
1067
+ and a ; Same as CP 0 but faster.
1068
+ ret z ; Back behind the call print if A = 0
1069
+ call CHPUT ; Call the routine to display a character.
1070
+ inc hl ; Increment the HL value.
1071
+ jr Print ; Relative jump to the address in the label Print.
1072
+
1073
+ BDOS_WE:
1074
+ ld (0D000h),sp ; Store SP register
1075
+ jp BDOS
1076
+
1077
+ ; Data
1078
+
1079
+ NoDisk_TXT: ; Text pointer label
1080
+ db "No disk installed!",LF,CR
1081
+ db "Turn off the MSX.",0 ; Zero indicates the end of text
1082
+ Save_TXT:
1083
+ db "Saving",022h,"DATA.DAT",022h,"...",LF,CR,0
1084
+ SaveOK_TXT:
1085
+ db "File saved",LF,CR,0
1086
+ SaveERR_TXT:
1087
+ db "File error!!!",LF,CR,0
1088
+ InsDisk_TXT:
1089
+ db "Insert the floppy disk",LF,CR
1090
+ db "then press RETURN",LF,CR,0
1091
+
1092
+ ERR_Routine:
1093
+ dw InsDisk
1094
+
1095
+ FCB:
1096
+ db 0,"DATA DAT"
1097
+ ds 116,0 ; Fill the rest of FCB with 00h
1098
+
1099
+ ds RomSize - ($ & (RomSize-1)),255 ; Fill the unused aera in page with 0FFh
1100
+ ```
1101
+
1102
+ ## Create a ROM with mapper
1103
+
1104
+ MegaRom's mappers are not standardized. The main existing mappers are described on the page [here](https://www.msx.org/wiki/MegaROM_Mappers). In addition, how to assemble your program to the MegaRom format also depends on the assembler used. Please refer to the manual for how to manage the segments. Below are some examples. If your assembler can not create a ROM for mapper, you will have to assemble each segment separately and merge them together with concat, or use the instruction INCBIN in an extra program in assembler. You can create a jump table to make the link between the segments for example.
1105
+
1106
+ ### Examples to make a 128kB ROM for ASCII 16k mapper
1107
+
1108
+ #### Example for Glass assembler
1109
+
1110
+ ```
1111
+ ; Example to create an MegaRom of 128kB that use an ASCII 16K Mapper
1112
+ ; for glass assembler
1113
+
1114
+ Seg0: ds 4000H
1115
+ Seg1: ds 4000H
1116
+ Seg2: ds 4000H
1117
+ Seg3: ds 4000H
1118
+ Seg4: ds 4000H
1119
+ Seg5: ds 4000H
1120
+ Seg6: ds 4000H
1121
+ Seg7: ds 4000H
1122
+
1123
+ LF: equ 0Ah
1124
+ CR: equ 0Dh
1125
+
1126
+ CHPUT: equ 00A2h ; Address of character output routine of main Rom BIOS
1127
+ ENASLT: equ 0024h
1128
+ INIT32: equ 006Fh
1129
+ RSLREG: equ 0138h
1130
+
1131
+ Seg_P8000_SW: equ 7000h ; Segment switch on page 8000h-BFFFh (ASCII 16k Mapper)
1132
+
1133
+ LINL32: equ 0F3AFh
1134
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
1135
+
1136
+ SECTION Seg0
1137
+
1138
+ org 4000h
1139
+
1140
+ db 41h,42h
1141
+ dw INIT,0,0,0,0,0,0
1142
+
1143
+ INIT:
1144
+ ld a,32
1145
+ ld (LINL32),a ; 32 columns
1146
+ call INIT32 ; SCREEN 1
1147
+
1148
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7FFFh
1149
+
1150
+ call GetSlotPage1
1151
+ ld h,080h
1152
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
1153
+
1154
+ ld a,1
1155
+ LOOP:
1156
+ ld (Seg_P8000_SW),a ; Select the segment on page 8000h-BFFFh
1157
+
1158
+ push af
1159
+ ld hl,Seg1_TXT ; Text pointer into HL
1160
+ call Print ; Call the routine Print below
1161
+ pop af
1162
+
1163
+ inc a ; Increment segment number
1164
+ cp 8
1165
+ jr nz,LOOP ; Jump to LOOP if A<8
1166
+
1167
+ Finished:
1168
+ jr Finished ; Jump to itself endlessly.
1169
+
1170
+ ; Gets the slot selected in page 1 (4000h-7FFFh)
1171
+ ; a <- slot ID
1172
+ GetSlotPage1:
1173
+ call RSLREG
1174
+ rrca
1175
+ rrca
1176
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
1177
+ ld c,a
1178
+ ld b,0
1179
+ ld hl,EXPTBL
1180
+ add hl,bc
1181
+ ld a,(hl)
1182
+ and 80h
1183
+ or c
1184
+ ld c,a
1185
+ inc hl
1186
+ inc hl
1187
+ inc hl
1188
+ inc hl
1189
+ ld a,(hl)
1190
+ and 0Ch
1191
+ or c
1192
+ ret
1193
+
1194
+ Print:
1195
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
1196
+ and a ; Same as CP 0 but faster.
1197
+ ret z ; Back behind the call print if A = 0
1198
+ call CHPUT ; Call the routine to display a character.
1199
+ inc hl ; Increment the HL value.
1200
+ jr Print ; Jump to the address in the label Print.
1201
+
1202
+ ENDS
1203
+
1204
+ SECTION Seg1
1205
+ org 8000h
1206
+
1207
+ Seg1_TXT: ; Text pointer label
1208
+ db "Text from segment 1",LF,CR,0 ; Zero indicates the end of text.
1209
+ ENDS
1210
+
1211
+ SECTION Seg2
1212
+ org 8000h
1213
+
1214
+ db "Text from segment 2",LF,CR,0
1215
+ ENDS
1216
+
1217
+ SECTION Seg3
1218
+ org 8000h
1219
+
1220
+ db "Text from segment 3",LF,CR,0
1221
+ ENDS
1222
+
1223
+ SECTION Seg4
1224
+ org 8000h
1225
+
1226
+ db "Text from segment 4",LF,CR,0
1227
+ ENDS
1228
+
1229
+ SECTION Seg5
1230
+ org 8000h
1231
+
1232
+ db "Text from segment 5",LF,CR,0
1233
+ ENDS
1234
+
1235
+ SECTION Seg6
1236
+ org 8000h
1237
+
1238
+ db "Text from segment 6",LF,CR,0
1239
+ ENDS
1240
+
1241
+ SECTION Seg7
1242
+ org 8000h
1243
+
1244
+ db "Text from segment 7",LF,CR,0
1245
+ ENDS
1246
+ ```
1247
+
1248
+ #### Example for Sjasm assembler
1249
+
1250
+ Do not forget the space or tabulation in the front of directives defpage and page.
1251
+
1252
+ ```
1253
+ ; Example to create an MegaRom of 128kB that use an ASCII 16K Mapper
1254
+ ; for Sjasm assembler
1255
+
1256
+ output ASC16tst.ROM
1257
+
1258
+ LF: equ 0Ah
1259
+ CR: equ 0Dh
1260
+
1261
+ ENASLT: equ 0024h
1262
+ INIT32: equ 006Fh
1263
+ CHPUT: equ 00A2h ; Address of character output routine of main Rom BIOS
1264
+ RSLREG: equ 0138h
1265
+
1266
+ PageSize: equ 04000h ; 16kB
1267
+ Seg_P8000_SW: equ 07000h ; Segment switch for page 8000h-BFFFh (ASCII 16k Mapper)
1268
+
1269
+ LINL32: equ 0F3AFh
1270
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
1271
+
1272
+ defpage 0,4000H,PageSize
1273
+ page 0
1274
+
1275
+ db 41h,42h
1276
+ dw INIT,0,0,0,0,0,0
1277
+
1278
+ INIT:
1279
+ ld a,32
1280
+ ld (LINL32),a ; 32 columns
1281
+ call INIT32 ; SCREEN 1
1282
+
1283
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7BFFFh
1284
+
1285
+ call RSLREG
1286
+ rrca
1287
+ rrca
1288
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
1289
+ ld c,a
1290
+ ld b,0
1291
+ ld hl,EXPTBL
1292
+ add hl,bc
1293
+ ld a,(hl)
1294
+ and 80h
1295
+ or c
1296
+ ld c,a
1297
+ inc hl
1298
+ inc hl
1299
+ inc hl
1300
+ inc hl
1301
+ ld a,(hl)
1302
+ and 0Ch
1303
+ or c
1304
+ ld h,080h
1305
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
1306
+
1307
+ ld a,1
1308
+ LOOP:
1309
+ ld (Seg_P8000_SW),a ; Select the segment on page 8000h-BFFFh
1310
+
1311
+ push af
1312
+ ld hl,Seg1_TXT ; Text pointer into HL
1313
+ call Print ; Call the routine Print below
1314
+ pop af
1315
+
1316
+ inc a ; Increment segment number
1317
+ cp 8
1318
+ jr nz, LOOP ; Jump to LOOP if A<8
1319
+
1320
+ Finished:
1321
+ jr Finished ; Jump to itself endlessly.
1322
+
1323
+ Print:
1324
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
1325
+ and a ; Same as CP 0 but faster.
1326
+ ret z ; Back behind the call print if A = 0
1327
+ call CHPUT ; Call the routine to display a character.
1328
+ inc hl ; Increment the HL value.
1329
+ jr Print ; Jump to the address in the label Print.
1330
+
1331
+ defpage 1,8000H,PageSize
1332
+ page 1
1333
+
1334
+ Seg1_TXT: ; Text pointer label
1335
+ db "Text from segment 1",LF,CR,0 ; Zero indicates the end of text.
1336
+
1337
+ defpage 2,8000H,PageSize
1338
+ page 2
1339
+
1340
+ db "Text from segment 2",LF,CR,0
1341
+
1342
+ defpage 3,8000H,PageSize
1343
+ page 3
1344
+
1345
+ db "Text from segment 3",LF,CR,0
1346
+
1347
+ defpage 4,8000H,PageSize
1348
+ page 4
1349
+
1350
+ db "Text from segment 4",LF,CR,0
1351
+
1352
+ defpage 5,8000H,PageSize
1353
+ page 5
1354
+
1355
+ db "Text from segment 5",LF,CR,0
1356
+
1357
+ defpage 6,8000H,PageSize
1358
+ page 6
1359
+
1360
+ db "Text from segment 6",LF,CR,0
1361
+
1362
+ defpage 7,8000H,PageSize
1363
+ page 7
1364
+
1365
+ db "Text from segment 7",LF,CR,0
1366
+ ```
1367
+
1368
+ #### Example for tniASM assembler
1369
+
1370
+ ```
1371
+ ; Example to create an MegaRom of 128kB that use an ASCII 16K Mapper
1372
+ ; for tniASM assembler
1373
+
1374
+ fname "ASC16tst.ROM"
1375
+
1376
+ LF: equ 0Ah
1377
+ CR: equ 0Dh
1378
+
1379
+ ENASLT: equ 0024h
1380
+ INIT32: equ 006Fh
1381
+ CHPUT: equ 00A2h ; Address of character output routine of main Rom BIOS
1382
+ RSLREG: equ 0138h
1383
+
1384
+ PageSize: equ 04000h ; 16kB
1385
+ Seg_P8000_SW: equ 07000h ; Segment switch for page 8000h-BFFFh (ASCII 16k Mapper)
1386
+
1387
+ LINL32: equ 0F3AFh
1388
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
1389
+
1390
+ org 4000h,7FFFh ; Page 0
1391
+
1392
+ dw "AB",INIT,0,0,0,0,0,0
1393
+
1394
+ INIT:
1395
+ ld a,32
1396
+ ld (LINL32),a ; 32 columns
1397
+ call INIT32 ; SCREEN 1
1398
+
1399
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7BFFFh
1400
+
1401
+ call RSLREG
1402
+ rrca
1403
+ rrca
1404
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
1405
+ ld c,a
1406
+ ld b,0
1407
+ ld hl,EXPTBL
1408
+ add hl,bc
1409
+ ld a,(hl)
1410
+ and 80h
1411
+ or c
1412
+ ld c,a
1413
+ inc hl
1414
+ inc hl
1415
+ inc hl
1416
+ inc hl
1417
+ ld a,(hl)
1418
+ and 0Ch
1419
+ or c
1420
+ ld h,080h
1421
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
1422
+
1423
+ ld a,1
1424
+ LOOP:
1425
+ ld (Seg_P8000_SW),a
1426
+
1427
+ push af
1428
+ ld hl,Seg1_TXT ; Text pointer into HL
1429
+ call Print ; Call the routine Print below
1430
+ pop af
1431
+
1432
+ inc a
1433
+ cp 8
1434
+ jr nz, LOOP ; Jump to LOOP if A<8
1435
+
1436
+ Finished:
1437
+ jr Finished ; Jump to itself endlessly.
1438
+
1439
+ Print:
1440
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
1441
+ and a ; Same as CP 0 but faster.
1442
+ ret z ; Back behind the call print if A = 0
1443
+ call CHPUT ; Call the routine to display a character.
1444
+ inc hl ; Increment the HL value.
1445
+ jr Print ; Jump to the address in the label Print.
1446
+
1447
+ ds PageSize - ($ - 4000h),255 ; Fill the unused aera with 0FFh
1448
+
1449
+ org 8000h,0BFFFh ; page 1
1450
+
1451
+ Seg1_TXT: ; Text pointer label
1452
+ db "Text from segment 1",LF,CR,0 ; Zero indicates the end of text.
1453
+ ds PageSize - ($ - 8000h),255 ; Fill the unused aera with 0FFh
1454
+
1455
+ org 8000h,0BFFFh ; page 2
1456
+
1457
+ db "Text from segment 2",LF,CR,0
1458
+ ds PageSize - ($ - 8000h),255
1459
+
1460
+ org 8000h,0BFFFh ; page 3
1461
+
1462
+ db "Text from segment 3",LF,CR,0
1463
+ ds PageSize - ($ - 8000h),255
1464
+
1465
+ org 8000h,0BFFFh ; page 4
1466
+
1467
+ db "Text from segment 4",LF,CR,0
1468
+ ds PageSize - ($ - 8000h),255
1469
+
1470
+ org 8000h,0BFFFh ; page 5
1471
+
1472
+ db "Text from segment 5",LF,CR,0
1473
+ ds PageSize - ($ - 8000h),255
1474
+
1475
+ org 8000h,0BFFFh ; page 6
1476
+
1477
+ db "Text from segment 6",LF,CR,0
1478
+ ds PageSize - ($ - 8000h),255
1479
+
1480
+ org 8000h,0BFFFh ; page 7
1481
+
1482
+ db "Text from segment 7",LF,CR,0
1483
+ ds PageSize - ($ - 8000h),255
1484
+
1485
+ ```
1486
+
1487
+ #### Example for Zasm assembler
1488
+
1489
+ ```
1490
+ ; Example to create an MegaRom of 128kB that use an ASCII 16K Mapper
1491
+ ; for zasm assembler
1492
+
1493
+ LF: equ 0Ah
1494
+ CR: equ 0Dh
1495
+
1496
+ ENASLT: equ 0024h
1497
+ INIT32: equ 006Fh
1498
+ CHPUT: equ 00A2h ; Address of character output routine of main Rom BIOS
1499
+ RSLREG: equ 0138h
1500
+
1501
+ PageSize: equ 04000h ; 16kB
1502
+ Seg_P8000_SW: equ 07000h ; Segment switch on page 8000h-BFFFh (ASCII 16k Mapper)
1503
+
1504
+ LINL32: equ 0F3AFh
1505
+ EXPTBL: equ 0FCC1h ; Extended slot flags table (4 bytes)
1506
+
1507
+ #target rom
1508
+ #code Seg0,04000h,PageSize
1509
+
1510
+ ; ### ROM header ###
1511
+
1512
+ db 41h,42h
1513
+ dw INIT,0,0,0,0,0,0
1514
+
1515
+ INIT:
1516
+ ld a,32
1517
+ ld (LINL32),a ; 32 columns
1518
+ call INIT32 ; SCREEN 1
1519
+
1520
+ ; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7FFFh
1521
+
1522
+ call RSLREG
1523
+ rrca
1524
+ rrca
1525
+ and 3 ;Keep bits corresponding to the page 4000h-7FFFh
1526
+ ld c,a
1527
+ ld b,0
1528
+ ld hl,EXPTBL
1529
+ add hl,bc
1530
+ ld a,(hl)
1531
+ and 80h
1532
+ or c
1533
+ ld c,a
1534
+ inc hl
1535
+ inc hl
1536
+ inc hl
1537
+ inc hl
1538
+ ld a,(hl)
1539
+ and 0Ch
1540
+ or c
1541
+ ld h,080h
1542
+ call ENASLT ; Select the ROM on page 8000h-BFFFh
1543
+
1544
+ ld a,1
1545
+ LOOP:
1546
+ ld (Seg_P8000_SW),a ; Select the segment on page 8000h-BFFFh
1547
+
1548
+ push af
1549
+ ld hl,Seg1_TXT ; Text pointer into HL
1550
+ call Print ; Call the routine Print below
1551
+ pop af
1552
+
1553
+ inc a ; Increment segment number
1554
+ cp 8
1555
+ jr nz, LOOP ; Jump to LOOP if A<8
1556
+
1557
+ Finished:
1558
+ jr Finished ; Jump to itself endlessly.
1559
+
1560
+ Print:
1561
+ ld a,(hl) ; Load the byte from memory at address indicated by HL to A.
1562
+ and a ; Same as CP 0 but faster.
1563
+ ret z ; Back behind the call print if A = 0
1564
+ call CHPUT ; Call the routine to display a character.
1565
+ inc hl ; Increment the HL value.
1566
+ jr Print ; Jump to the address in the label Print.
1567
+
1568
+ #code Seg1,08000h,PageSize
1569
+
1570
+ Seg1_TXT: ; Text pointer label
1571
+ db "Text from segment 1",LF,CR,0 ; Zero indicates the end of text.
1572
+
1573
+ #code Seg2,08000h,PageSize
1574
+
1575
+ db "Text from segment 2",LF,CR,0
1576
+
1577
+ #code Seg3,08000h,PageSize
1578
+
1579
+ db "Text from segment 3",LF,CR,0
1580
+
1581
+ #code Seg4,08000h,PageSize
1582
+
1583
+ db "Text from segment 4",LF,CR,0
1584
+
1585
+ #code Seg5,08000h,PageSize
1586
+
1587
+ db "Text from segment 5",LF,CR,0
1588
+
1589
+ #code Seg6,08000h,PageSize
1590
+
1591
+ db "Text from segment 6",LF,CR,0
1592
+
1593
+ #code Seg7,08000h,PageSize
1594
+
1595
+ db "Text from segment 7",LF,CR,0
1596
+
1597
+ END
1598
+ ```
1599
+
1600
+ ## Search for RAM
1601
+
1602
+ For a ROM that supports disks you can use [this system variables](https://www.msx.org/wiki/How_to_detect_the_RAM).
1603
+
1604
+ For other ROMs you must search the RAM your self on each page as below example.
1605
+
1606
+ > **Note:** Variables RAMAD0-RAMAD3 are used in examples but you can use any other free memory instead since these variables are used by the system only when a disk is installed.
1607
+
1608
+ ```
1609
+ ; Routine of search for RAM on each page from MSX cartridge
1610
+ ;
1611
+ ; Output: RAMAD0-RAMAD3 = Slot number of Main-RAM for corresponding page
1612
+
1613
+ RDSLT: equ 0000Ch ; Read a byte in a Slot
1614
+ RSLREG: equ 00138h ; Read primary Slot REGister
1615
+ WRSLT: equ 00014h ; Write a byte in a Slot
1616
+ WSLREG: equ 0013Bh ; Write primary Slot REGister
1617
+
1618
+ RomSize: equ 04000h
1619
+
1620
+ EXPTBL: equ 0FCC1h ; Expanded Slot Table
1621
+ SLTTBL equ 0FCC5h ; Slot Table
1622
+ KBUF: equ 0F41Fh ; Temporary data
1623
+ RAMAD0: equ 0F341h ; Main-RAM Slot (00000h~03FFFh)
1624
+ RAMAD1: equ 0F342h ; Main-RAM Slot (04000h~07FFFh)
1625
+ RAMAD2: equ 0F343h ; Main-RAM Slot (08000h~0BFFFh)
1626
+ RAMAD3: equ 0F344h ; Main-RAM Slot (0C000h~0FFFFh)
1627
+ RAMSLT: equ KBUF+3
1628
+
1629
+ org 04000h ; Can be also 8000h
1630
+
1631
+ ; ### ROM header ###
1632
+
1633
+ db 041h,042h
1634
+ dw INIT,0,0,0,0,0,0
1635
+
1636
+ INIT:
1637
+
1638
+ def_RAMAD3:
1639
+ call RSLREG
1640
+ and 0C0h
1641
+ rlca
1642
+ rlca ; A = Primary slot
1643
+ ld c,a
1644
+ ld b,0
1645
+ ld hl,EXPTBL
1646
+ add hl,bc
1647
+ ld a,(hl)
1648
+ and 80h
1649
+ jr z,No_SS3 ; Jump if slot is not secondary (page 3)
1650
+
1651
+ ld hl,SLTTBL
1652
+ add hl,bc
1653
+ ld a,(hl) ; A = Value of current decondary slots register
1654
+ and 0C0h ; Keep the bits for page 3
1655
+ rrca
1656
+ rrca
1657
+ rrca
1658
+ rrca ; Bits 2-3 of A = Current secondary slot (page 2)
1659
+ or 080h ; Set the bit 7
1660
+ No_SS3:
1661
+ or c
1662
+ ld (RAMAD3),a ; Bit7=1 if extended Slot
1663
+
1664
+ def_RAMAD2:
1665
+
1666
+ ld hl,08000h
1667
+ call ram_srch
1668
+ ld (RAMAD2),a
1669
+
1670
+ def_RAMAD1:
1671
+
1672
+ ld hl,04000h
1673
+ call ram_srch
1674
+ ld (RAMAD1),a
1675
+
1676
+ def_RAMAD0:
1677
+
1678
+ ld hl,00000h
1679
+ call ram_srch
1680
+ ld (RAMAD0),a
1681
+
1682
+ NeverEndLoop:
1683
+ jr NeverEndLoop
1684
+
1685
+ ; Search RAM on a page
1686
+ ; Input: HL=0000h, 4000h or 8000h
1687
+ ; output: A=slot number and Carry = 0, Carry = 1 if Ram not found
1688
+
1689
+ ram_srch:
1690
+ ld b,4 ;Slot primaire
1691
+ ram_srch_loop:
1692
+ ld a,b
1693
+ dec a
1694
+ xor 3
1695
+ ld (RAMSLT),a
1696
+ ld e,a
1697
+
1698
+ push hl
1699
+ ld hl,EXPTBL
1700
+ ld d,0
1701
+ add hl,de
1702
+ ld a,(hl)
1703
+ ld (KBUF),a ; Save secondary slot flag
1704
+
1705
+ pop hl
1706
+ ld a,h
1707
+ exx
1708
+ ld h,a
1709
+ ld l,0 ; Restore HL address
1710
+
1711
+ ld a,(KBUF) ; Restore secondary slot flag
1712
+ rlca
1713
+ ld b,1
1714
+ ld a,(RAMSLT)
1715
+ jr nc,PrimSLT
1716
+
1717
+ ld b,4 ;Slot secondaire
1718
+ ram_srch_loop2:
1719
+ ld a,b
1720
+ dec a
1721
+ xor 3
1722
+ rlca
1723
+ rlca
1724
+ ld c,a
1725
+ ld a,(RAMSLT)
1726
+ or c
1727
+ or 080h ; Set bit 7
1728
+ PrimSLT:
1729
+ ld (KBUF+1),a
1730
+ push bc
1731
+ call RDSLT
1732
+ ld (KBUF+2),a
1733
+ pop bc
1734
+ cp 041h
1735
+ jr nz,no_header ; Jump if first byte = "A" (Rom?)
1736
+
1737
+ inc hl
1738
+ ld a,(KBUF+1)
1739
+ push bc
1740
+ call RDSLT
1741
+ pop bc
1742
+ dec hl
1743
+ cp 042h
1744
+ jr z,no_ram ; Jump if second byte <> "B"
1745
+ no_header:
1746
+ ld a,(KBUF+1)
1747
+ push bc
1748
+ call RDSLT ; Read first byte
1749
+ pop bc
1750
+ ld e,041h
1751
+ ld a,(KBUF+1)
1752
+ push bc
1753
+ call WRSLT ; Write "A" at first byte
1754
+ pop bc
1755
+ ld a,(KBUF+1)
1756
+ push bc
1757
+ call RDSLT ; Read first byte
1758
+ pop bc
1759
+ cp 041h
1760
+ jr z,ram_found ; Jump if first byte = "A"
1761
+
1762
+ no_ram:
1763
+ djnz ram_srch_loop2 ; Go to next Slot if No RAM
1764
+ exx
1765
+ djnz ram_srch_loop ; Go to next Slot if No RAM
1766
+ scf ; Set Carry
1767
+ ret
1768
+
1769
+ ram_found:
1770
+ ld a,(KBUF+2)
1771
+ ld e,a
1772
+ ld a,(KBUF+1)
1773
+ push af
1774
+ or 080h
1775
+ call WRSLT ; Restore first byte value of RAM
1776
+ pop af ; A=Slot of Ram found (without Bit7)
1777
+ or a ; Reset Carry
1778
+ ret
1779
+
1780
+ ds RomSize - ($ & (RomSize-1)),255 ; Fill the unused aera in page with 0FFh
1781
+ end
1782
+ ```
1783
+
1784
+ Use preferably the following example for the MSX turbo R because it uses its internal memory by default and the access to RAM is faster in R800 mode.
1785
+
1786
+ ```
1787
+ ; Routine of search for RAM on each page from MSX cartridge
1788
+ ;
1789
+ ; Output: RAMAD0-RAMAD3 = Slot number of Main-RAM for corresponding page
1790
+
1791
+ RDSLT: equ 0000Ch ; Read a byte in a Slot
1792
+ WRSLT: equ 00014h ; Write a byte in a Slot
1793
+ RSLREG: equ 00138h ; Read primary Slot REGister
1794
+ WSLREG: equ 0013Bh ; Write primary Slot REGister
1795
+ CHGCPU: equ 00180h
1796
+
1797
+ RAMAD0: equ 0F341h ; Main-RAM Slot (00000h~03FFFh)
1798
+ RAMAD1: equ 0F342h ; Main-RAM Slot (04000h~07FFFh)
1799
+ RAMAD2: equ 0F343h ; Main-RAM Slot (08000h~0BFFFh)
1800
+ RAMAD3: equ 0F344h ; Main-RAM Slot (0C000h~0FFFFh)
1801
+ EXPTBL: equ 0FCC1h ; Expanded Slot Table
1802
+ SLTTBL equ 0FCC5h ; Slot Table
1803
+
1804
+ org 04000h ; Can be also 8000h
1805
+
1806
+ ; ### ROM header ###
1807
+
1808
+ db 041h,042h
1809
+ dw INIT ; Main program execution address.
1810
+ dw 0 ; STATEMENT
1811
+ dw 0 ; DEVICE
1812
+ dw 0 ; TEXT (Unused on this page)
1813
+ dw 0,0,0 ; Reserved
1814
+
1815
+ INIT:
1816
+ ld a,082h
1817
+ call CHGCPU ; Select R800 mode with DRAM
1818
+
1819
+ def_RAMADx:
1820
+ call RSLREG
1821
+ and 0C0h
1822
+ rlca
1823
+ rlca ; A = Primary slot
1824
+ ld c,a
1825
+ ld b,0
1826
+ ld hl,EXPTBL
1827
+ add hl,bc
1828
+ ld a,(hl)
1829
+ and 80h
1830
+ jr z,No_SS3 ; Jump if slot is not secondary (page 3)
1831
+
1832
+ ld hl,SLTTBL
1833
+ add hl,bc
1834
+ ld a,(hl) ; A = Value of current decondary slots register
1835
+ and 0C0h ; Keep the bits for page 3
1836
+ rrca
1837
+ rrca
1838
+ rrca
1839
+ rrca ; Bits 2-3 of A = Current secondary slot (page 2)
1840
+ or 080h ; Set the bit 7
1841
+ No_SS3:
1842
+ or c
1843
+ ld (RAMAD3),a
1844
+ ld (RAMAD2),a
1845
+ ld (RAMAD1),a
1846
+ ld (RAMAD0),a
1847
+
1848
+ NeverEndLoop:
1849
+ jr NeverEndLoop
1850
+
1851
+ ds RomSize - ($ & (RomSize-1)),255 ; Fill the unused aera in page with 0FFh
1852
+ end
1853
+ ```
1854
+
1855
+ ## Allocate RAM (workarea)
1856
+
1857
+ In programs not requiring software from other cartridges (stand-alone
1858
+ software such as games), the portion with the smaller address than the work area used by BIOS (F380H) can be used freely.
1859
+
1860
+ But in programs which are executed by using BASIC interpreter functions, the same area cannot be shared as the work area. To do this, there are three methods:
1861
+
1862
+ 1. Place RAM on the cartridge itself (the safest and most reliable method).
1863
+ 2. When one or two bytes are needed for the work area, use two bytes corresponding to itself in SLTWRK (FD09h) as the work area.
1864
+ 3. When more than two bytes are needed for the work area, allocates it from RAM used by BASIC.
1865
+
1866
+ *Example code for method 2:*
1867
+ - A page1 extension ROM (4000H-7FFFH) with other extensions in the slot address space:[[1]](https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/examples/allocate_system_memory/alloc1.mac)
1868
+ - A page2 extension ROM (8000H-BFFFH) with other extensions in the slot address space:[[2]](https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/examples/allocate_system_memory/alloc2.mac)
1869
+ - A page1 extension ROM (4000H-7FFFH) exclusive slot address space **(8 bytes of workarea)**:[[3]](https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/examples/allocate_system_memory/allocs.mac)
1870
+
1871
+ *Example code for method 3:*
1872
+ - A page1 extension ROM (4000H-7FFFH) not supporting the MSX disksystem:[[4]](https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/examples/allocate_system_memory/allocn.mac)
1873
+ - A page1 extension ROM (4000H-7FFFH) supporting the MSX disksystem:[[5]](https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/examples/allocate_system_memory/allocd.mac)
1874
+
1875
+ ## Useful system Variables
1876
+
1877
+ | | | | |
1878
+ | --- | --- | --- | --- |
1879
+ | FCC9h | SLTATR | 64 | Slot attributes given during MSX boot process.<br/>`Bit 7 = 1 if Basic program, else 0`<br/>`Bit 6 = 1 if device extension, else 0`<br/>`Bit 5 = 1 if statement extension, else 0`<br/>`Bits 4~0 = Unused` |
1880
+ | FD09h | SLTWRK | 128 | SLTWRK is a 128-byte variable array used to reserve a RAM work area in Main-RAM for ROM applications. This array consists of 8 bytes per slot (2 per memory page). Each of these 2 octets are provided to place an slot ID with flags (first byte = Slot ID and the second is 00h) or an address on two bytes as follows.<br/>`SLTWRK+0 = Work area for slot 0-0, page 0000h~3FFFh`<br/>`SLTWRK+2 = Work area for slot 0-0, page 4000h~7FFFh`<br/>`SLTWRK+4 = Work area for slot 0-0, page 8000h~BFFFh`<br/>`SLTWRK+6 = Work area for slot 0-0, page C000h~FFFFh`<br/>`SLTWRK+8 = Work area for slot 0-1, page 0000h~3FFFh`<br/>`...`<br/>`SLTWRK+124 = Work area for slot 3-3, page 8000h~BFFFh`<br/>`SLTWRK+126 = Work area for slot 3-3, page C000h~FFFFh`<br/>The pointer is used to reserve a work area from 8000h or higher to F37Fh.<br/>The slot ID is used to reserve a work area on the pages 0000h~3FFFh & 4000h~7FFFh).<br/><br/>**Slot ID format used in table SLTWRK:**<br/>`Bits: 7(F) 6(RMD) 5(APP) 4(RES) 3(SS1) 2(SS0) 1(PS1) 0 (PS0)`<br/>- PS = Primary slot number<br/>- SS = Secondary slot number<br/>- RES = Reserved<br/>- APP = Set if the RAM used by an application, 0 otherwise<br/>- RMD = Set if the RAM is used by instruction CALL MEMINI, 0 otherwise<br/>- F = Set if secondary slot, 0 if primary slot.<br/><br/>Perform the following calculation to find the location reserved for your application in ROM.<br/>`Address = SLTWRK + 32\*PS + 8\*SS + 2\*page number`<br/><br/>Notes:<br/>- The array is not valid for the first 7 bytes because the system reserves them in the following way.<br/>- SLTWRK = Slot ID for the area reserved by CALL MEMINI. (MSX2~)<br/>- SLTWRK+1 = 2\*3 bytes for Kanji or Hangul modes of Japanese or Korean MSXs (SLTWRK + 4 indicates the Kanji Basic ROM Slot) |
1881
+ | FD89h | PROCNM | 16 | Work aera of the instructions CALL and OPEN. Contents the instruction name or device name. |