test_simm30_dram

view test.c @ 5:7d9b129a5791

convert to 30pin
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 04 Jun 2017 02:56:55 +0300
parents bd6ad00cb1bc
children
line source
1 /*
2 30pin SIMM DRAM tester.
3 Copyright (C) 2017 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 #define F_CPU XTAL
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <stdint.h>
25 #include <avr/io.h>
26 #include <avr/interrupt.h>
27 #include <util/delay.h>
28 #include "serial.h"
30 /* pin assignments:
31 * A[0,7] data
32 * B[0,7] A0 - A7
33 * C[0,3] A8 - A11
34 * D7 CAS
35 * D6 RAS
36 */
38 #define CAS_BIT 0x80
39 #define RAS_BIT 0x40
40 #define WE_BIT 0x04
42 void proc_cmd(char *cmd);
43 void cmd_read(char *buf);
44 void cmd_write(char *buf);
45 void cmd_setcfg(char *buf);
46 void cmd_test(char *buf);
47 void cmd_detect(void);
49 void dram_init(void);
50 void dram_detect(void);
51 int memtest(uint32_t addr);
52 void dram_refresh(void);
53 void dram_write(uint32_t addr, unsigned char val);
54 unsigned char dram_read(uint32_t addr);
56 #define MAX_INPUT_SIZE 128
57 static char input[MAX_INPUT_SIZE];
58 static unsigned char inp_cidx;
60 /* SIMM access config */
61 static int addr_bits;
62 static uint32_t addr_mask;
63 static long memsize_kb; /* derived from the above */
65 int main(void)
66 {
67 dram_init();
68 init_serial(38400);
69 sei();
71 printf("\n72pin SIMM DRAM tester by John Tsiombikas <nuclear@member.fsf.org>\n");
73 cmd_detect();
75 fputs("> ", stdout);
77 for(;;) {
78 if(have_input()) {
79 int c = getchar();
80 putchar(c);
82 if(c == '\r' || c == '\n') {
83 input[inp_cidx] = 0;
84 proc_cmd(input);
85 inp_cidx = 0;
87 fputs("> ", stdout);
88 } else if(inp_cidx < sizeof input - 1) {
89 input[inp_cidx++] = c;
90 }
91 }
93 dram_refresh();
94 }
95 return 0;
96 }
98 void proc_cmd(char *cmd)
99 {
100 switch(cmd[0]) {
101 case 'w':
102 cmd_write(cmd + 1);
103 break;
105 case 'r':
106 cmd_read(cmd + 1);
107 break;
109 case 's':
110 cmd_setcfg(cmd + 1);
111 break;
113 case 't':
114 cmd_test(cmd + 1);
115 break;
117 case 'd':
118 cmd_detect();
119 break;
121 case 'h':
122 printf("commands:\n");
123 printf(" w <addr> <value> - write byte to address\n");
124 printf(" r <addr> - read byte from address\n");
125 printf(" s <addr_bits|ras_lines> <value>\n");
126 printf(" t <addr> - test address\n");
127 printf(" d - detect DRAM\n");
128 printf(" h - help\n");
129 break;
130 }
131 }
133 void cmd_read(char *buf)
134 {
135 char *endp;
136 uint32_t addr;
137 unsigned char data;
139 addr = strtol(buf, &endp, 0);
140 if(endp == buf) {
141 fprintf(stderr, "invalid argument to write command: %s\n", buf);
142 return;
143 }
144 buf = endp;
146 data = dram_read(addr);
147 printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
148 }
150 void cmd_write(char *buf)
151 {
152 char *endp;
153 uint32_t addr;
154 unsigned char data;
156 addr = strtol(buf, &endp, 0);
157 if(endp == buf) {
158 fprintf(stderr, "invalid address argument to read command: %s\n", buf);
159 return;
160 }
161 buf = endp;
163 data = strtol(buf, &endp, 0);
164 if(endp == buf) {
165 fprintf(stderr, "invalid data argument to read command: %s\n", buf);
166 return;
167 }
168 buf = endp;
170 dram_write(addr, data);
171 printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
172 }
174 void cmd_setcfg(char *buf)
175 {
176 char *endp;
177 char *name, *valstr;
178 long value;
180 name = buf;
181 while(*name && isspace(*name)) ++name;
182 if(!*name) {
183 fprintf(stderr, "invalid or missing variable name\n");
184 return;
185 }
186 endp = name;
187 while(*endp && !isspace(*endp)) ++endp;
188 *endp = 0;
190 valstr = endp + 1;
191 value = strtol(valstr, &endp, 0);
192 if(endp == valstr) {
193 fprintf(stderr, "invalid or missing variable value: %s\n", valstr);
194 return;
195 }
197 if(strcmp(name, "addr_bits") == 0) {
198 if(value > 0 && value <= 12) {
199 addr_bits = value;
200 addr_mask = ((uint32_t)1 << addr_bits) - 1;
201 printf("Address bits: %ld (mask: %lx)\n", value, (unsigned long)addr_mask);
202 } else {
203 fprintf(stderr, "invalid address bits value: %ld\n", value);
204 }
205 } else {
206 fprintf(stderr, "unknown variable: %s\n", name);
207 }
208 }
210 void cmd_test(char *buf)
211 {
212 char *endp;
213 uint32_t addr;
215 addr = strtol(buf, &endp, 0);
216 if(endp == buf) {
217 fprintf(stderr, "invalid argument to test command: %s\n", buf);
218 return;
219 }
221 if(memtest(addr) == 0) {
222 printf("success!\n");
223 }
224 }
227 void cmd_detect(void)
228 {
229 printf("Detecting memory ...\n");
230 dram_detect();
232 memsize_kb = ((uint32_t)1 << addr_bits);
234 printf("Address lines: %d\n", addr_bits);
235 printf("Memory size: %ldmb (%ldkb)\n", memsize_kb >> 20, memsize_kb >> 10);
236 }
239 void dram_set_data(unsigned char val)
240 {
241 DDRA = 0xff;
242 PORTA = val;
243 }
245 void dram_release_data(void)
246 {
247 DDRA = 0;
248 PORTA = 0;
249 }
251 void dram_set_addr(unsigned long addr)
252 {
253 PORTB = addr & 0xff;
254 PORTC = (addr >> 8) & 3;
255 }
257 void dram_assert_cas(void)
258 {
259 PORTD &= ~CAS_BIT;
260 }
262 void dram_release_cas(void)
263 {
264 PORTD |= CAS_BIT;
265 }
267 void dram_assert_ras(void)
268 {
269 PORTD &= ~RAS_BIT;
270 }
272 void dram_release_ras(void)
273 {
274 PORTD |= RAS_BIT;
275 }
277 void dram_set_we(void)
278 {
279 PORTD &= ~WE_BIT;
280 }
282 void dram_clear_we(void)
283 {
284 PORTD |= WE_BIT;
285 }
287 void dram_init(void)
288 {
289 DDRA = 0; /* port A is the data bus */
290 PORTA = 0; /* no pullups when A is input */
291 DDRB = 0xff; /* port B is A0-A7 */
292 DDRC = 0xff; /* port C (low nibble) is A8-A11 */
293 DDRD = 0xff; /* port D are the control lines CAS/RAS/WR */
295 PORTD = 0xff; /* deassert all control signals */
297 /* it seems like nothing works until we do one refresh cycle... */
298 dram_refresh();
299 }
301 void dram_detect(void)
302 {
303 uint32_t addr = 0;
305 /* detect how many address bits we've got */
306 addr_bits = 12;
307 while(addr_bits > 8) {
308 addr_mask = ((uint32_t)1 << (uint32_t)addr_bits) - 1;
309 addr = ((uint32_t)1 << ((uint32_t)addr_bits * 2)) - 1;
310 if(memtest(addr) == 0) {
311 break;
312 }
313 --addr_bits;
314 }
315 if(addr_bits < 1) {
316 fprintf(stderr, "Failed to detect DRAM configuration (address lines)...\n");
317 return;
318 }
319 }
321 int memtest(uint32_t addr)
322 {
323 int i;
324 unsigned char pat[] = { 0xf0, 0x0f, 0xaa, 0x55, 0xc0, 0x30, 0x0c, 0x03 };
325 unsigned char val;
327 printf("testing address: %lx (a:%d)\n", (unsigned long)addr, addr_bits);
329 for(i=0; i<sizeof pat / sizeof *pat; i++) {
330 dram_write(addr, pat[i]);
331 if((val = dram_read(addr)) != pat[i]) {
332 printf("pattern %x failed, got: %x\n", (unsigned int)pat[i], (unsigned int)val);
333 return -1;
334 }
335 }
336 return 0;
337 }
339 void dram_refresh(void)
340 {
341 dram_assert_cas();
342 dram_assert_ras();
343 dram_release_cas();
344 dram_release_ras();
345 }
347 void dram_write(uint32_t addr, unsigned char val)
348 {
349 uint32_t row_addr = (addr >> addr_bits) & addr_mask;
350 uint32_t col_addr = addr & addr_mask;
352 dram_set_data(val);
353 dram_set_we();
354 /* set row address */
355 dram_set_addr(row_addr);
356 dram_assert_ras();
357 /* set column address */
358 dram_set_addr(col_addr);
359 dram_assert_cas();
360 dram_release_ras();
361 dram_release_cas();
362 dram_release_data();
363 dram_clear_we();
364 }
366 unsigned char dram_read(uint32_t addr)
367 {
368 unsigned char val;
369 uint32_t row_addr = (addr >> addr_bits) & addr_mask;
370 uint32_t col_addr = addr & addr_mask;
372 dram_clear_we();
373 /* this is necessary to remove previous data from the lines when no-one is driving them
374 * in case we're trying to detect the presence of a RAS line which doesn't exist
375 */
376 dram_set_data(0);
377 dram_release_data();
379 /* set row address */
380 dram_set_addr(row_addr);
381 dram_assert_ras();
382 /* set column address */
383 dram_set_addr(col_addr);
384 dram_assert_cas();
386 val = PINA;
388 dram_release_ras();
389 dram_release_cas();
391 return val;
392 }