gbasys
view src/comm.c @ 12:a6ddf338a111
line clipping
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 01 Feb 2016 04:41:27 +0200 |
parents | 06726f0b8cd3 |
children |
line source
1 /*
2 gbasys - a gameboy advance hardware abstraction library
3 Copyright (C) 2004-2014 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "comm.h"
19 #include "error.h"
20 #include "signal.h"
21 #include "intr.h"
23 #define REG_SIODATA32 *((volatile unsigned short*)0x4000120)
24 #define REG_SIOCNT *((volatile unsigned short*)0x4000128)
25 #define REG_SIODATA8 *((volatile unsigned short*)0x400012a)
26 #define REG_RCNT *((volatile unsigned short*)0x4000134)
28 /* REG_SIOCNT bits */
29 #define SIOCNT_CLK_INTERN (1 << 0)
30 #define SIOCNT_CLK_2MHZ (1 << 1)
31 #define SIOCNT_RECV_ENABLE (1 << 2)
32 #define SIOCNT_SEND_ENABLE (1 << 3)
33 #define SIOCNT_START (1 << 7)
34 #define SIOCNT_XFER_LEN (1 << 12)
35 #define SIOCNT_INT_ENABLE (1 << 14)
37 /* only in 16bit multi player mode */
38 #define SIOCNT_BAUD_38400 1
39 #define SIOCNT_BAUD_57600 2
40 #define SIOCNT_BAUD_115200 3
41 #define SIOCNT_SI_STATUS (1 << 2)
42 #define SIOCNT_SD_STATUS (1 << 3)
43 #define SIOCNT_SLAVE1 (1 << 4)
44 #define SIOCNT_SLAVE2 (2 << 4)
45 #define SIOCNT_SLAVE3 (3 << 4)
46 #define SIOCNT_ERROR (1 << 6)
48 /* REG_RCNT bits */
49 #define RCNT_GPIO_DATA_MASK 0x000f
50 #define RCNT_GPIO_DIR_MASK 0x00f0
51 #define RCNT_GPIO_INT_ENABLE (1 << 8)
52 #define RCNT_MODE_GPIO 0x8000
53 #define RCNT_MODE_JOYBUS 0xc000
56 static void setup_sio(int bits, int ms);
57 static void setup_gpio(void);
58 static void comm_intr(void);
60 static int sio_bits, sio_master;
61 static void *sio_buf;
64 void comm_setup(int mode)
65 {
66 int master = 0;
68 mask(INTR_COMM);
69 interrupt(INTR_COMM, comm_intr);
70 unmask(INTR_COMM);
72 switch(mode) {
73 case COMM_SIO8_MASTER:
74 master = 1;
75 case COMM_SIO8_SLAVE:
76 setup_sio(8, master);
77 break;
79 case COMM_SIO32_MASTER:
80 master = 1;
81 case COMM_SIO32_SLAVE:
82 setup_sio(32, master);
83 break;
85 case COMM_GPIO:
86 setup_gpio();
87 break;
89 default:
90 panic("unimplemented comm mode\n");
91 }
92 }
94 static void setup_sio(int bits, int ms)
95 {
96 REG_RCNT = 0; /* serial mode */
98 sio_bits = bits;
99 sio_master = ms;
100 }
102 void sio_transfer(void *in, const void *out)
103 {
104 /* load outgoing data */
105 if(sio_bits <= 8) {
106 REG_SIODATA8 = *(unsigned char*)out;
107 } else {
108 REG_SIODATA32 = *(unsigned long*)out;
109 }
110 sio_buf = in;
112 /* IE=1, external clock, send enable */
113 REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE;
115 /* start transfer */
116 REG_SIOCNT |= SIOCNT_START;
118 /* wait until the transfer is complete */
119 while(REG_SIOCNT & SIOCNT_START);
120 }
122 void sio_transfer_async(void *in, const void *out)
123 {
124 /* load outgoing data */
125 if(sio_bits <= 8) {
126 REG_SIODATA8 = *(unsigned char*)out;
127 } else {
128 REG_SIODATA32 = *(unsigned long*)out;
129 }
130 sio_buf = in;
132 /* IE=1, external clock, send enable */
133 REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE;
135 /* start transfer */
136 REG_SIOCNT |= SIOCNT_START;
137 }
140 static void setup_gpio(void)
141 {
142 REG_RCNT = RCNT_MODE_GPIO | RCNT_GPIO_INT_ENABLE;
143 }
145 void gpio_dir(int dir_so, int dir_si, int dir_sd, int dir_sc)
146 {
147 unsigned char mask;
149 mask = ((dir_so & 1) << 7) | ((dir_si & 1) << 6) | ((dir_sd & 1) << 5) |
150 ((dir_sc & 1) << 4);
151 gpio_dir_mask(mask);
152 }
154 void gpio_dir_mask(unsigned char dir)
155 {
156 REG_RCNT = (REG_RCNT & 0xff0f) | ((dir & 0xf) << 4);
157 }
159 void gpio_set(unsigned char val)
160 {
161 REG_RCNT = (REG_RCNT & 0xfff0) | (val & 0xf);
162 }
164 unsigned char gpio_get(void)
165 {
166 return REG_RCNT & 0xf;
167 }
169 static void comm_intr(void)
170 {
171 if(sio_buf) {
172 if(REG_SIOCNT & SIOCNT_START) {
173 panic("asio: interrupt with start bit == 1");
174 }
175 if(sio_bits <= 8) {
176 *(unsigned char*)sio_buf = REG_SIODATA8;
177 } else {
178 *(unsigned long*)sio_buf = REG_SIODATA32;
179 }
180 sio_buf = 0;
181 }
183 if(signal_func(SIGIO)) {
184 raise(SIGIO);
185 }
186 }