-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLynxGD.c
213 lines (183 loc) · 4.88 KB
/
LynxGD.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <6502.h>
#include <lynx.h>
#include <tgi.h>
#include <peekpoke.h>
#include <string.h>
#include <joystick.h>
#include "LynxGD.h"
////////////////////////////////////////////////////////////////////////////////
//
// Microcontroller communication constants
//
////////////////////////////////////////////////////////////////////////////////
typedef enum
{
ECommandByte_OpenDir = 0,
ECommandByte_ReadDir,
ECommandByte_OpenFile,
ECommandByte_GetSize,
ECommandByte_Seek,
ECommandByte_Read,
ECommandByte_Write,
ECommandByte_Close,
ECommandByte_ProgramFile,
ECommandByte_ClearBlocks,
ECommandByte_LowPowerMode
} ECommandByte;
////////////////////////////////////////////////////////////////////////////////
//
// Lynx registers
//
////////////////////////////////////////////////////////////////////////////////
const u8 AUXMASK = 16;
#define IODAT ((volatile u8 *) 0xFD8B)
#define IODIR ((volatile u8 *) 0xFD8A)
#define CART1 ((volatile u8 *) 0xFCB3)
#define CART0 ((volatile u8 *) 0xFCB2)
////////////////////////////////////////////////////////////////////////////////
//
// Support functions to read and write bytes to the cartridge microcontroller
//
////////////////////////////////////////////////////////////////////////////////
static void __fastcall__ WriteByte(u8 byte)
{
while (*IODAT & AUXMASK); // make sure the cart isnt blocking the write
*CART1 = byte;
}
static void __fastcall__ WriteBytes(u8 *pBuf, u16 nSize)
{
while (nSize--)
{
WriteByte(*pBuf++);
}
}
static void __fastcall__ WriteWord(u16 word)
{
WriteBytes((u8*) &word, 2);
}
static void __fastcall__ WriteDword(u32 dword)
{
WriteBytes((u8*) &dword, 4);
}
static u8 ReadByte()
{
while (!(*IODAT & AUXMASK)); // wait for data in read FIFO
return *CART0; // read byte
}
static void __fastcall__ ReadBytes(u8 *pOut, u16 size)
{
while (size--)
{
*pOut++ = ReadByte();
}
}
static u32 ReadDword()
{
u32 nDword;
ReadBytes((u8*) &nDword, 4);
return nDword;
}
static void __fastcall__ WriteString(const char *pStr)
{
char c;
do
{
c = *pStr++;
WriteByte(c);
} while (c);
}
////////////////////////////////////////////////////////////////////////////////
//
// Microcontroller commands
//
////////////////////////////////////////////////////////////////////////////////
void LynxGD_Init()
{
*IODIR = 0; // all input
}
void LynxGD_LowPowerMode()
{
WriteByte(ECommandByte_LowPowerMode); // turn off memory card and enter low power state
}
FRESULT __fastcall__ LynxGD_OpenDir(const char *pDir)
{
WriteByte(ECommandByte_OpenDir); // open dir command
WriteString(pDir);
return (FRESULT) ReadByte(); // read the response
}
FRESULT __fastcall__ LynxGD_ReadDir(SFileInfo *pInfo)
{
FRESULT res;
WriteByte(ECommandByte_ReadDir);
res = (FRESULT) ReadByte();
if (res == FR_OK)
{
ReadBytes((u8 *) pInfo, sizeof(SFileInfo));
}
return res;
}
FRESULT __fastcall__ LynxGD_OpenFile(const char *pFile)
{
WriteByte(ECommandByte_OpenFile); // open file command
WriteString(pFile);
return (FRESULT) ReadByte(); // read the response
}
FRESULT __fastcall__ LynxGD_ReadFile(void *pBuffer, u16 nSize)
{
WriteByte(ECommandByte_Read);
WriteWord(nSize);
ReadBytes((u8 *) pBuffer, nSize);
return (FRESULT) ReadByte(); // final byte is status for read
}
FRESULT __fastcall__ LynxGD_WriteFile(void *pBuffer, u16 nSize)
{
WriteByte(ECommandByte_Write);
WriteWord(nSize);
WriteBytes((u8 *) pBuffer, nSize);
return (FRESULT) ReadByte(); // final byte is status for write
}
FRESULT LynxGD_CloseFile()
{
WriteByte(ECommandByte_Close);
return (FRESULT) ReadByte(); // status for close
}
FRESULT __fastcall__ LynxGD_SeekFile(u32 nSeekPos)
{
WriteByte(ECommandByte_Seek);
WriteDword(nSeekPos);
return (FRESULT) ReadByte(); // seek result
}
u32 LynxGD_GetFileSize()
{
WriteByte(ECommandByte_GetSize);
return ReadDword(); // size of open file
}
FRESULT __fastcall__ LynxGD_ProgramROMFromFile(u16 nStartBlock, u8 nBlockSize, u16 nBlockCount, u8 b512BlockCard)
{
if (b512BlockCard)
{
nBlockSize |= 0x10;
}
WriteByte(ECommandByte_ProgramFile);
WriteWord(nStartBlock); // start block from 0-511 (>255 with 512 block card bit set)
WriteByte(nBlockSize); // or with 0x10 for 512 block card (a19 controlled by aux pin)
WriteWord(nBlockCount); // blocks to write
return (FRESULT) ReadByte(); // waits for programming to end and gets result
}
FRESULT __fastcall__ LynxGD_ClearROMBlocks(u16 nStartBlock, u16 nBlocks, u8 b512BlockCard)
{
if (b512BlockCard)
{
nBlocks |= 0x8000;
}
WriteByte(ECommandByte_ClearBlocks);
WriteWord(nStartBlock); // start block from 0-511 (>255 with 512 block card bit set)
WriteWord(nBlocks); // or with 0x8000 for 512 block card (a19 controlled by aux pin)
return (FRESULT) ReadByte(); // waits for clearing to end and gets result
}