test_simm30_dram

view test.c @ 2:42d26388b709

memory detection works
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 09 Mar 2017 01:40:31 +0200
parents 318a758ede82
children bd6ad00cb1bc
line source
1 #define F_CPU XTAL
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <stdint.h>
8 #include <avr/io.h>
9 #include <avr/interrupt.h>
10 #include <util/delay.h>
11 #include "serial.h"
13 /* pin assignments:
14 * A[0,7] data
15 * B[0,7] A0 - A7
16 * C[0,3] A8 - A11
17 * D7 CAS3
18 * D6 RAS2
19 * D5 RAS3
20 */
22 #define CAS3_BIT 0x80
23 #define RAS2_BIT 0x40
24 #define RAS3_BIT 0x20
25 #define WE_BIT 0x04
27 void proc_cmd(char *cmd);
28 void cmd_read(char *buf);
29 void cmd_write(char *buf);
30 void cmd_setcfg(char *buf);
31 void cmd_test(char *buf);
32 void cmd_detect(void);
34 void dram_init(void);
35 void dram_detect(void);
36 int memtest(uint32_t addr);
37 void dram_refresh(void);
38 void dram_write(uint32_t addr, unsigned char val);
39 unsigned char dram_read(uint32_t addr);
41 #define MAX_INPUT_SIZE 128
42 static char input[MAX_INPUT_SIZE];
43 static unsigned char inp_cidx;
45 /* SIMM access config */
46 static int addr_bits;
47 static uint32_t addr_mask;
48 static int ras_lines = 1;
49 static long memsize_kb; /* derived from the above */
51 int main(void)
52 {
53 dram_init();
54 init_serial(38400);
55 sei();
57 printf("\n72pin SIMM DRAM tester by John Tsiombikas <nuclear@member.fsf.org>\n");
59 cmd_detect();
61 fputs("> ", stdout);
63 for(;;) {
64 if(have_input()) {
65 int c = getchar();
66 putchar(c);
68 if(c == '\r' || c == '\n') {
69 input[inp_cidx] = 0;
70 proc_cmd(input);
71 inp_cidx = 0;
73 fputs("> ", stdout);
74 } else if(inp_cidx < sizeof input - 1) {
75 input[inp_cidx++] = c;
76 }
77 }
79 dram_refresh();
80 }
81 return 0;
82 }
84 void proc_cmd(char *cmd)
85 {
86 switch(cmd[0]) {
87 case 'w':
88 cmd_write(cmd + 1);
89 break;
91 case 'r':
92 cmd_read(cmd + 1);
93 break;
95 case 's':
96 cmd_setcfg(cmd + 1);
97 break;
99 case 't':
100 cmd_test(cmd + 1);
101 break;
103 case 'd':
104 cmd_detect();
105 break;
107 case 'h':
108 printf("commands:\n");
109 printf(" w <addr> <value> - write byte to address\n");
110 printf(" r <addr> - read byte from address\n");
111 printf(" s <addr_bits|ras_lines> <value>\n");
112 printf(" t <addr> - test address\n");
113 printf(" d - detect DRAM\n");
114 printf(" h - help\n");
115 break;
116 }
117 }
119 void cmd_read(char *buf)
120 {
121 char *endp;
122 uint32_t addr;
123 unsigned char data;
125 addr = strtol(buf, &endp, 0);
126 if(endp == buf) {
127 fprintf(stderr, "invalid argument to write command: %s\n", buf);
128 return;
129 }
130 buf = endp;
132 data = dram_read(addr);
133 printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
134 }
136 void cmd_write(char *buf)
137 {
138 char *endp;
139 uint32_t addr;
140 unsigned char data;
142 addr = strtol(buf, &endp, 0);
143 if(endp == buf) {
144 fprintf(stderr, "invalid address argument to read command: %s\n", buf);
145 return;
146 }
147 buf = endp;
149 data = strtol(buf, &endp, 0);
150 if(endp == buf) {
151 fprintf(stderr, "invalid data argument to read command: %s\n", buf);
152 return;
153 }
154 buf = endp;
156 dram_write(addr, data);
157 printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
158 }
160 void cmd_setcfg(char *buf)
161 {
162 char *endp;
163 char *name, *valstr;
164 long value;
166 name = buf;
167 while(*name && isspace(*name)) ++name;
168 if(!*name) {
169 fprintf(stderr, "invalid or missing variable name\n");
170 return;
171 }
172 endp = name;
173 while(*endp && !isspace(*endp)) ++endp;
174 *endp = 0;
176 valstr = endp + 1;
177 value = strtol(valstr, &endp, 0);
178 if(endp == valstr) {
179 fprintf(stderr, "invalid or missing variable value: %s\n", valstr);
180 return;
181 }
183 if(strcmp(name, "addr_bits") == 0) {
184 if(value > 0 && value <= 12) {
185 addr_bits = value;
186 addr_mask = ((uint32_t)1 << addr_bits) - 1;
187 printf("Address bits: %ld (mask: %lx)\n", value, (unsigned long)addr_mask);
188 } else {
189 fprintf(stderr, "invalid address bits value: %ld\n", value);
190 }
191 } else if(strcmp(name, "ras_lines") == 0) {
192 if(value > 0 && value <= 2) {
193 ras_lines = value;
194 printf("RAS lines: %d\n", ras_lines);
195 } else {
196 fprintf(stderr, "invalid RAS lines value: %ld\n", value);
197 }
198 } else {
199 fprintf(stderr, "unknown variable: %s\n", name);
200 }
201 }
203 void cmd_test(char *buf)
204 {
205 char *endp;
206 uint32_t addr;
208 addr = strtol(buf, &endp, 0);
209 if(endp == buf) {
210 fprintf(stderr, "invalid argument to test command: %s\n", buf);
211 return;
212 }
214 if(memtest(addr) == 0) {
215 printf("success!\n");
216 }
217 }
220 void cmd_detect(void)
221 {
222 printf("Detecting memory ...\n");
223 dram_detect();
225 memsize_kb = ((uint32_t)1 << (addr_bits * 2)) * 4 * ras_lines;
227 printf("Address lines: %d\n", addr_bits);
228 printf("RAS lines: %d\n", ras_lines);
229 printf("Memory size: %ldmb (%ldkb)\n", memsize_kb >> 20, memsize_kb >> 10);
230 }
233 void dram_set_data(unsigned char val)
234 {
235 DDRA = 0xff;
236 PORTA = val;
237 }
239 void dram_release_data(void)
240 {
241 DDRA = 0;
242 PORTA = 0;
243 }
245 void dram_set_addr(unsigned long addr)
246 {
247 PORTB = addr & 0xff;
248 PORTC = (addr >> 8) & 3;
249 }
251 void dram_assert_cas(void)
252 {
253 PORTD &= ~CAS3_BIT;
254 }
256 void dram_release_cas(void)
257 {
258 PORTD |= CAS3_BIT;
259 }
261 void dram_assert_ras(unsigned char bits)
262 {
263 PORTD &= ~bits;
264 }
266 void dram_release_ras(unsigned char bits)
267 {
268 PORTD |= bits;
269 }
271 void dram_set_we(void)
272 {
273 PORTD &= ~WE_BIT;
274 }
276 void dram_clear_we(void)
277 {
278 PORTD |= WE_BIT;
279 }
281 void dram_init(void)
282 {
283 DDRA = 0; /* port A is the data bus */
284 PORTA = 0; /* no pullups when A is input */
285 DDRB = 0xff; /* port B is A0-A7 */
286 DDRC = 0xff; /* port C (low nibble) is A8-A11 */
287 DDRD = 0xff; /* port D are the control lines CAS/RAS/WR */
289 PORTD = 0xff; /* deassert all control signals */
291 /* it seems like nothing works until we do one refresh cycle... */
292 dram_refresh();
293 }
295 void dram_detect(void)
296 {
297 uint32_t addr = 0;
299 /* detect how many address bits we've got */
300 addr_bits = 12;
301 while(addr_bits > 8) {
302 addr_mask = ((uint32_t)1 << (uint32_t)addr_bits) - 1;
303 addr = ((uint32_t)1 << ((uint32_t)addr_bits * 2)) - 1;
304 if(memtest(addr) == 0) {
305 break;
306 }
307 --addr_bits;
308 }
309 if(addr_bits < 1) {
310 fprintf(stderr, "Failed to detect DRAM configuration (address lines)...\n");
311 return;
312 }
314 /* now detect if there's a second ras pair */
315 ++addr; /* addr was already the highest of the first bank, see if there's a second */
316 ras_lines = 2;
317 if(memtest(addr) != 0) {
318 ras_lines = 1;
319 }
320 }
322 int memtest(uint32_t addr)
323 {
324 int i;
325 unsigned char pat[] = { 0xf0, 0x0f, 0xaa, 0x55, 0xc0, 0x30, 0x0c, 0x03 };
326 unsigned char val;
328 printf("testing address: %lx (a:%d,r:%d)\n", (unsigned long)addr, addr_bits, ras_lines);
330 for(i=0; i<sizeof pat / sizeof *pat; i++) {
331 dram_write(addr, pat[i]);
332 if((val = dram_read(addr)) != pat[i]) {
333 printf("pattern %x failed, got: %x\n", (unsigned int)pat[i], (unsigned int)val);
334 return -1;
335 }
336 }
337 return 0;
338 }
340 void dram_refresh(void)
341 {
342 dram_assert_cas();
343 dram_assert_ras(RAS2_BIT | RAS3_BIT);
344 dram_release_cas();
345 dram_release_ras(RAS2_BIT | RAS3_BIT);
346 }
348 void dram_write(uint32_t addr, unsigned char val)
349 {
350 uint32_t row_addr = (addr >> addr_bits) & addr_mask;
351 uint32_t col_addr = addr & addr_mask;
352 unsigned char ras = (addr >> (addr_bits * 2)) ? RAS3_BIT : RAS2_BIT;
354 dram_set_data(val);
355 dram_set_we();
356 /* set row address */
357 dram_set_addr(row_addr);
358 dram_assert_ras(ras);
359 /* set column address */
360 dram_set_addr(col_addr);
361 dram_assert_cas();
362 dram_release_ras(ras);
363 dram_release_cas();
364 dram_release_data();
365 dram_clear_we();
366 }
368 unsigned char dram_read(uint32_t addr)
369 {
370 unsigned char val;
371 uint32_t row_addr = (addr >> addr_bits) & addr_mask;
372 uint32_t col_addr = addr & addr_mask;
373 unsigned char ras = (addr >> (addr_bits * 2)) ? RAS3_BIT : RAS2_BIT;
375 dram_clear_we();
376 /* this is necessary to remove previous data from the lines when no-one is driving them
377 * in case we're trying to detect the presence of a RAS line which doesn't exist
378 */
379 dram_set_data(0);
380 dram_release_data();
382 /* set row address */
383 dram_set_addr(row_addr);
384 dram_assert_ras(ras);
385 /* set column address */
386 dram_set_addr(col_addr);
387 dram_assert_cas();
389 val = PINA;
391 dram_release_ras(ras);
392 dram_release_cas();
394 return val;
395 }