Skip to content

Commit 6dbf1e5

Browse files
committed
BIOS API: Present the CARD function as a C interface
Provide additional helper functions for checking the state of the memory card prior to calling the BIOS function.
1 parent 8da5b7c commit 6dbf1e5

8 files changed

Lines changed: 400 additions & 5 deletions

File tree

include/ngdevkit/_utils.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Private utility functions, not meant to be included directly
3+
* Copyright (c) 2026 Damien Ciabrini
4+
* This file is part of ngdevkit
5+
*
6+
* ngdevkit is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as
8+
* published by the Free Software Foundation, either version 3 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* ngdevkit is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with ngdevkit. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef __NGDEVKIT__UTILS_H__
21+
#define __NGDEVKIT__UTILS_H__
22+
23+
24+
/** Allow to preserve a specific set of register prior to calling
25+
* calling a function. This can bee handy when the called function
26+
* does not follow the caller/callee-safe convention.
27+
*/
28+
#define __SAVE_REGS_AND_CALL(regs, fun) \
29+
__asm__ volatile ( \
30+
"movem.l " regs ",%%sp@-\n" \
31+
"jsr %m0.l\n" \
32+
"movem.l %%sp@+, " regs "\n" \
33+
: /* no output */ \
34+
: "m" (fun) /* input */ \
35+
: "d0", "d1", "a0", "a1" /* clobbers */ \
36+
);
37+
38+
39+
#endif /* __NGDEVKIT__UTILS_H__ */

include/ngdevkit/bios-calls.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* BIOS system calls
3-
* Copyright (c) 2020-2025 Damien Ciabrini
3+
* Copyright (c) 2020-2026 Damien Ciabrini
44
* This file is part of ngdevkit
55
*
66
* ngdevkit is free software: you can redistribute it and/or modify
@@ -20,6 +20,7 @@
2020
#ifndef __NGDEVKIT_BIOS_CALLS_H__
2121
#define __NGDEVKIT_BIOS_CALLS_H__
2222

23+
2324
/* These are low-level bios call, not meant to be called directly */
2425
void bios_system_int1(void);
2526
void bios_system_int2(void);
@@ -55,9 +56,11 @@ void bios_lsp_1st(void);
5556

5657
void bios_mess_out(void);
5758

58-
void bios_card(void);
59-
60-
void bios_card_error(void);
59+
/* Memory-card related BIOS functions:
60+
* - void bios_card(void);
61+
* - void bios_card_error(void);
62+
*/
63+
#include <ngdevkit/memory-card.h>
6164

6265
void bios_how_to_play(void);
6366

@@ -70,6 +73,8 @@ void bios_cd_data_ready(void);
7073
void bios_cd_data_transfer(void);
7174

7275

76+
/* Addresses of BIOS functions, suitable for C and ASM */
7377
#include <ngdevkit/asm/bios-calls.h>
7478

79+
7580
#endif /* __NGDEVKIT_BIOS_CALLS_H__ */

include/ngdevkit/memory-card.h

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
* Copyright (c) 2026 Damien Ciabrini
3+
* This file is part of ngdevkit
4+
*
5+
* ngdevkit is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* ngdevkit is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with ngdevkit. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#ifndef __NGDEVKIT_MEMORY_CARD_H__
20+
#define __NGDEVKIT_MEMORY_CARD_H__
21+
22+
#include <stdbool.h>
23+
#include <ngdevkit/types.h>
24+
#include <ngdevkit/_utils.h>
25+
26+
#ifdef __cplusplus
27+
extern "C" {
28+
#endif
29+
30+
31+
/**
32+
* Memory card command to be run by BIOS function `bios_card`
33+
*/
34+
extern u8 bios_card_command;
35+
36+
/* TODO: undocumented */
37+
/* extern u8 bios_card_mode; */
38+
39+
/**
40+
* Error code returned by BIOS function `bios_card`
41+
*/
42+
extern u8 bios_card_answer;
43+
44+
/**
45+
* Pointer in RAM to hold memory card's save data
46+
*/
47+
extern u32 bios_card_start;
48+
49+
/**
50+
* Size of a memory card's save data
51+
*/
52+
extern u16 bios_card_size;
53+
54+
/**
55+
* NGH number to be used for the memory card's save data.
56+
* the number has a BCD representation
57+
*/
58+
extern u16 bios_card_fcb;
59+
60+
/**
61+
* Bitfield to reference the 16 possible save slot of a
62+
* particular game in the memory card.
63+
*/
64+
extern u16 bios_card_sub;
65+
66+
67+
/**
68+
* Check whether a memory card is inserted into the system.
69+
*/
70+
bool ng_memory_card_inserted(void);
71+
72+
/**
73+
* Check whether the inserted memory card is write-protected.
74+
*
75+
* This function assumes that the memory card is already inserted.
76+
* Use `ng_memory_card_inserted` if you need to check it.
77+
*/
78+
bool ng_memory_card_write_protected(void);
79+
80+
/**
81+
* Allow writing to the memory card.
82+
*
83+
* Configure the status register to allow writes to the memory card.
84+
* This function must be called before running BIOS function
85+
* `bios_card` to allow it to write to the memory card.
86+
* After calling the BIOS function, the write status goes back
87+
* to 'locked' automatically.
88+
*/
89+
void ng_memory_card_unlock(void);
90+
91+
/**
92+
* Prevent writing to the memory card.
93+
*
94+
* Configure the status register to prevent writes to the memory card.
95+
* Note that the status is set to 'locked' automatically after
96+
* BIOS function `bios_card` ran a write command, so it is not
97+
* necessary to call this function directly.
98+
*/
99+
void ng_memory_card_lock(void);
100+
101+
/**
102+
* BIOS API: run a memory card command.
103+
*
104+
* Prior to calling this function, the command to be run must be
105+
* set in variable `bios_card_command`. If the command involves
106+
* writing to the memory card, you must unlock write access with
107+
* `ng_memory_card_unlock` prior to calling this BIOS function.
108+
*
109+
* Memory card commands read parameters from global variables.
110+
* - `bios_card_start`: pointer to start of data in RAM
111+
* - `bios_card_size`: size of transferred data
112+
* - `bios_card_sub`: saved slot(s) for this game (bitfield)
113+
* - `bios_card_fcb`: NGH number for this game (BCD format)
114+
*
115+
* The result of the BIOS call is an error code set in variable
116+
* `bios_card_answer`.
117+
*
118+
* More info at https://wiki.neogeodev.org/index.php?title=CARD
119+
*/
120+
void bios_card(void);
121+
122+
/**
123+
* Memory card command: format memory card
124+
* Inputs: N/A
125+
* Output: N/A
126+
*/
127+
#define MC_CMD_FORMAT 0x0
128+
129+
/**
130+
* Memory card command: number of saved entries for a game
131+
* Inputs:
132+
* - `bios_card_fcb`: game NGH number
133+
* Output:
134+
* - `bios_card_sub`: a bit for every saved slot used for this game
135+
*/
136+
#define MC_CMD_DATA_SEARCH 0x1
137+
138+
/**
139+
* Memory card command: load data
140+
* Inputs:
141+
* - `bios_card_fcb`: game NGH number
142+
* - `bios_card_sub`: save slot to use (bit)
143+
* - `bios_card_start`: address in RAM that will hold loaded data
144+
* - `bios_card_size`: size of data to load (usually 64 bytes)
145+
* Output: N/A
146+
*/
147+
#define MC_CMD_LOAD_DATA 0x2
148+
149+
/**
150+
* Memory card command: save data
151+
* Inputs:
152+
* - `bios_card_fcb`: game NGH number
153+
* - `bios_card_sub`: save slot to use (bit)
154+
* - `bios_card_start`: address in RAM of data to save
155+
* - `bios_card_size`: size of data to save (usually 64 bytes)
156+
* Output: N/A
157+
*/
158+
#define MC_CMD_SAVE_DATA 0x3
159+
160+
/**
161+
* Memory card command: delete a specific save slot for a game
162+
* Inputs:
163+
* - `bios_card_fcb`: game NGH number
164+
* - `bios_card_sub`: save slot to delete (bit)
165+
* Output: N/A
166+
*/
167+
168+
#define MC_CMD_DELETE_DATA 0x4
169+
170+
/**
171+
* Memory card command: TODO
172+
* Inputs: TODO
173+
* Output: TODO
174+
*/
175+
#define MC_CMD_DATA_TITLE 0x5
176+
177+
/**
178+
* Memory card command: set the memory card's user name
179+
* Inputs:
180+
* - `bios_card_start`: user name's address in RAM
181+
* Output:
182+
*/
183+
#define MC_CMD_SAVE_USER_NAME 0x6
184+
185+
/**
186+
* Memory card command: get the memory card's user name
187+
* Inputs:
188+
* - `bios_card_start`: user name's address in RAM
189+
* Output:
190+
*/
191+
#define MC_CMD_LOAD_USER_NAME 0x7
192+
193+
194+
/**
195+
* Memory card answer
196+
*
197+
* Error code returned by a call to `bios_card`
198+
* - 0x00: normal completion
199+
* - 0x80: no card inserted
200+
* - 0x81: card isn't formatted
201+
* - 0x82: requested data does not exist
202+
* - 0x83: FAT error
203+
* - 0x84: card is full
204+
* - 0x85: write disabled
205+
*/
206+
#define MC_ERR_OK 0x0
207+
#define MC_ERR_NO_CARD 0x80
208+
#define MC_ERR_NOT_FORMATTED 0x81
209+
#define MC_ERR_DATA_DOES_NOT_EXIST 0x82
210+
#define MC_ERR_FAT_ERROR 0x83
211+
#define MC_ERR_CARD_FULL 0x84
212+
#define MC_ERR_WRITE_DISABLED 0x85
213+
214+
/**
215+
* BIOS API: display memory card error and interactive recovery
216+
*
217+
* Let the BIOS present a human-readable status when a call to
218+
* `bios_card` returned an error.
219+
* Based on the error, the BIOS might present an interactive
220+
* menu to recover from the error (e.g. card full).
221+
*
222+
* More info at https://wiki.neogeodev.org/index.php?title=CARD
223+
*/
224+
void bios_card_error(void);
225+
226+
227+
228+
/* NOTE: we shadow the previous declarations with C macros, as some of
229+
* the BIOS functions do not preserve registers. This way, C code can
230+
* call the BIOS functions by their original name, while preserving
231+
* callee-saved registers as expected.
232+
*/
233+
234+
#define bios_card() do { __SAVE_REGS_AND_CALL("%%d2-%%d7/%%a2-%%a6", bios_card); } while(0)
235+
236+
237+
#ifdef __cplusplus
238+
}
239+
#endif
240+
241+
#endif /* __NGDEVKIT_MEMORY_CARD_H__ */

runtime/Makefile.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ NGDEVKIT_OBJS=\
4646
ng_center_text_tall_args \
4747
ng_center_text_args \
4848
ng_cls_args \
49-
ng_wait_vblank
49+
ng_wait_vblank \
50+
ng_memory_card_inserted \
51+
ng_memory_card_write_protected \
52+
ng_memory_card_unlock \
53+
ng_memory_card_lock
5054

5155
NGDEVKIT_CFLAGS=-I../include -std=c99 -fomit-frame-pointer
5256
NGDEVKIT_OPTS=-O0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2026 Damien Ciabrini
3+
* This file is part of ngdevkit
4+
*
5+
* ngdevkit is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* ngdevkit is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with ngdevkit. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include <ngdevkit/memory-card.h>
20+
#include <ngdevkit/registers.h>
21+
22+
23+
bool ng_memory_card_inserted(void) {
24+
return (*REG_STATUS_B & 0x30) == 0;
25+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2026 Damien Ciabrini
3+
* This file is part of ngdevkit
4+
*
5+
* ngdevkit is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* ngdevkit is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with ngdevkit. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include <ngdevkit/memory-card.h>
20+
#include <ngdevkit/registers.h>
21+
22+
23+
void ng_memory_card_lock(void) {
24+
// The memory card is deemed locked in software only after the two
25+
// memory-mapped lock bits have been set.
26+
*REG_CRDLOCK1 = 1;
27+
*REG_CRDLOCK2 = 1;
28+
}

0 commit comments

Comments
 (0)