test_simm30_dram

changeset 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
files test.c
diffstat 1 files changed, 98 insertions(+), 33 deletions(-) [+]
line diff
     1.1 --- a/test.c	Wed Mar 08 09:05:19 2017 +0200
     1.2 +++ b/test.c	Thu Mar 09 01:40:31 2017 +0200
     1.3 @@ -1,9 +1,13 @@
     1.4 +#define F_CPU	XTAL
     1.5 +
     1.6  #include <stdio.h>
     1.7  #include <stdlib.h>
     1.8  #include <string.h>
     1.9  #include <ctype.h>
    1.10 +#include <stdint.h>
    1.11  #include <avr/io.h>
    1.12  #include <avr/interrupt.h>
    1.13 +#include <util/delay.h>
    1.14  #include "serial.h"
    1.15  
    1.16  /* pin assignments:
    1.17 @@ -24,13 +28,15 @@
    1.18  void cmd_read(char *buf);
    1.19  void cmd_write(char *buf);
    1.20  void cmd_setcfg(char *buf);
    1.21 +void cmd_test(char *buf);
    1.22 +void cmd_detect(void);
    1.23  
    1.24  void dram_init(void);
    1.25  void dram_detect(void);
    1.26 -int memtest(unsigned long addr);
    1.27 +int memtest(uint32_t addr);
    1.28  void dram_refresh(void);
    1.29 -void dram_write(unsigned long addr, unsigned char val);
    1.30 -unsigned char dram_read(unsigned long addr);
    1.31 +void dram_write(uint32_t addr, unsigned char val);
    1.32 +unsigned char dram_read(uint32_t addr);
    1.33  
    1.34  #define MAX_INPUT_SIZE	128
    1.35  static char input[MAX_INPUT_SIZE];
    1.36 @@ -38,29 +44,24 @@
    1.37  
    1.38  /* SIMM access config */
    1.39  static int addr_bits;
    1.40 -static unsigned long addr_mask;
    1.41 +static uint32_t addr_mask;
    1.42  static int ras_lines = 1;
    1.43  static long memsize_kb;	/* derived from the above */
    1.44  
    1.45 -
    1.46  int main(void)
    1.47  {
    1.48  	dram_init();
    1.49  	init_serial(38400);
    1.50  	sei();
    1.51  
    1.52 -	printf("Detecting memory ...\n");
    1.53 -	dram_detect();
    1.54 +	printf("\n72pin SIMM DRAM tester by John Tsiombikas <nuclear@member.fsf.org>\n");
    1.55  
    1.56 -	memsize_kb = (1 << (addr_bits * 2)) * 4 * ras_lines;
    1.57 +	cmd_detect();
    1.58  
    1.59 -	printf("Address lines: %d\n", addr_bits);
    1.60 -	printf("RAS lines: %d\n", ras_lines);
    1.61 -	printf("Memory size: %ldmb (%ldkb)\n", memsize_kb >> 10, memsize_kb);
    1.62  	fputs("> ", stdout);
    1.63  
    1.64  	for(;;) {
    1.65 -		while(have_input()) {
    1.66 +		if(have_input()) {
    1.67  			int c = getchar();
    1.68  			putchar(c);
    1.69  
    1.70 @@ -95,11 +96,21 @@
    1.71  		cmd_setcfg(cmd + 1);
    1.72  		break;
    1.73  
    1.74 +	case 't':
    1.75 +		cmd_test(cmd + 1);
    1.76 +		break;
    1.77 +
    1.78 +	case 'd':
    1.79 +		cmd_detect();
    1.80 +		break;
    1.81 +
    1.82  	case 'h':
    1.83  		printf("commands:\n");
    1.84  		printf(" w <addr> <value> - write byte to address\n");
    1.85  		printf(" r <addr> - read byte from address\n");
    1.86  		printf(" s <addr_bits|ras_lines> <value>\n");
    1.87 +		printf(" t <addr> - test address\n");
    1.88 +		printf(" d - detect DRAM\n");
    1.89  		printf(" h - help\n");
    1.90  		break;
    1.91  	}
    1.92 @@ -108,7 +119,7 @@
    1.93  void cmd_read(char *buf)
    1.94  {
    1.95  	char *endp;
    1.96 -	unsigned long addr;
    1.97 +	uint32_t addr;
    1.98  	unsigned char data;
    1.99  
   1.100  	addr = strtol(buf, &endp, 0);
   1.101 @@ -119,13 +130,13 @@
   1.102  	buf = endp;
   1.103  
   1.104  	data = dram_read(addr);
   1.105 -	printf("%04lx: %02x (%u)\n", addr, (unsigned int)data, (unsigned int)data);
   1.106 +	printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
   1.107  }
   1.108  
   1.109  void cmd_write(char *buf)
   1.110  {
   1.111  	char *endp;
   1.112 -	unsigned long addr;
   1.113 +	uint32_t addr;
   1.114  	unsigned char data;
   1.115  
   1.116  	addr = strtol(buf, &endp, 0);
   1.117 @@ -143,7 +154,7 @@
   1.118  	buf = endp;
   1.119  
   1.120  	dram_write(addr, data);
   1.121 -	printf("%04lx: %02x (%u)\n", addr, (unsigned int)data, (unsigned int)data);
   1.122 +	printf("%04lx: %02x (%u)\n", (unsigned long)addr, (unsigned int)data, (unsigned int)data);
   1.123  }
   1.124  
   1.125  void cmd_setcfg(char *buf)
   1.126 @@ -172,7 +183,8 @@
   1.127  	if(strcmp(name, "addr_bits") == 0) {
   1.128  		if(value > 0 && value <= 12) {
   1.129  			addr_bits = value;
   1.130 -			printf("Address bits: %ld\n", value);
   1.131 +			addr_mask = ((uint32_t)1 << addr_bits) - 1;
   1.132 +			printf("Address bits: %ld (mask: %lx)\n", value, (unsigned long)addr_mask);
   1.133  		} else {
   1.134  			fprintf(stderr, "invalid address bits value: %ld\n", value);
   1.135  		}
   1.136 @@ -188,6 +200,36 @@
   1.137  	}
   1.138  }
   1.139  
   1.140 +void cmd_test(char *buf)
   1.141 +{
   1.142 +	char *endp;
   1.143 +	uint32_t addr;
   1.144 +
   1.145 +	addr = strtol(buf, &endp, 0);
   1.146 +	if(endp == buf) {
   1.147 +		fprintf(stderr, "invalid argument to test command: %s\n", buf);
   1.148 +		return;
   1.149 +	}
   1.150 +
   1.151 +	if(memtest(addr) == 0) {
   1.152 +		printf("success!\n");
   1.153 +	}
   1.154 +}
   1.155 +
   1.156 +
   1.157 +void cmd_detect(void)
   1.158 +{
   1.159 +	printf("Detecting memory ...\n");
   1.160 +	dram_detect();
   1.161 +
   1.162 +	memsize_kb = ((uint32_t)1 << (addr_bits * 2)) * 4 * ras_lines;
   1.163 +
   1.164 +	printf("Address lines: %d\n", addr_bits);
   1.165 +	printf("RAS lines: %d\n", ras_lines);
   1.166 +	printf("Memory size: %ldmb (%ldkb)\n", memsize_kb >> 20, memsize_kb >> 10);
   1.167 +}
   1.168 +
   1.169 +
   1.170  void dram_set_data(unsigned char val)
   1.171  {
   1.172  	DDRA = 0xff;
   1.173 @@ -245,16 +287,21 @@
   1.174  	DDRD = 0xff;	/* port D are the control lines CAS/RAS/WR */
   1.175  
   1.176  	PORTD = 0xff;	/* deassert all control signals */
   1.177 +
   1.178 +	/* it seems like nothing works until we do one refresh cycle... */
   1.179 +	dram_refresh();
   1.180  }
   1.181  
   1.182  void dram_detect(void)
   1.183  {
   1.184 +	uint32_t addr = 0;
   1.185 +
   1.186  	/* detect how many address bits we've got */
   1.187  	addr_bits = 12;
   1.188  	while(addr_bits > 8) {
   1.189 -		printf("addr mask: %lu\n", (unsigned long)((1 << (unsigned long)addr_bits) - 1));
   1.190 -		addr_mask = (1 << (unsigned long)addr_bits) - 1;
   1.191 -		if(memtest((1 << ((unsigned long)addr_bits * 2)) - 1) == 0) {
   1.192 +		addr_mask = ((uint32_t)1 << (uint32_t)addr_bits) - 1;
   1.193 +		addr = ((uint32_t)1 << ((uint32_t)addr_bits * 2)) - 1;
   1.194 +		if(memtest(addr) == 0) {
   1.195  			break;
   1.196  		}
   1.197  		--addr_bits;
   1.198 @@ -263,20 +310,27 @@
   1.199  		fprintf(stderr, "Failed to detect DRAM configuration (address lines)...\n");
   1.200  		return;
   1.201  	}
   1.202 +
   1.203 +	/* now detect if there's a second ras pair */
   1.204 +	++addr;	/* addr was already the highest of the first bank, see if there's a second */
   1.205 +	ras_lines = 2;
   1.206 +	if(memtest(addr) != 0) {
   1.207 +		ras_lines = 1;
   1.208 +	}
   1.209  }
   1.210  
   1.211 -int memtest(unsigned long addr)
   1.212 +int memtest(uint32_t addr)
   1.213  {
   1.214  	int i;
   1.215  	unsigned char pat[] = { 0xf0, 0x0f, 0xaa, 0x55, 0xc0, 0x30, 0x0c, 0x03 };
   1.216  	unsigned char val;
   1.217  
   1.218 -	printf("testing address: %lx (a:%d,r:%d)\n", addr, addr_bits, ras_lines);
   1.219 +	printf("testing address: %lx (a:%d,r:%d)\n", (unsigned long)addr, addr_bits, ras_lines);
   1.220  
   1.221  	for(i=0; i<sizeof pat / sizeof *pat; i++) {
   1.222  		dram_write(addr, pat[i]);
   1.223  		if((val = dram_read(addr)) != pat[i]) {
   1.224 -			printf("pattern %x failed, got: %x\n", (int)pat[i], val);
   1.225 +			printf("pattern %x failed, got: %x\n", (unsigned int)pat[i], (unsigned int)val);
   1.226  			return -1;
   1.227  		}
   1.228  	}
   1.229 @@ -291,39 +345,50 @@
   1.230  	dram_release_ras(RAS2_BIT | RAS3_BIT);
   1.231  }
   1.232  
   1.233 -void dram_write(unsigned long addr, unsigned char val)
   1.234 +void dram_write(uint32_t addr, unsigned char val)
   1.235  {
   1.236 +	uint32_t row_addr = (addr >> addr_bits) & addr_mask;
   1.237 +	uint32_t col_addr = addr & addr_mask;
   1.238 +	unsigned char ras = (addr >> (addr_bits * 2)) ? RAS3_BIT : RAS2_BIT;
   1.239 +
   1.240  	dram_set_data(val);
   1.241  	dram_set_we();
   1.242  	/* set row address */
   1.243 -	dram_set_addr((addr >> addr_bits) & addr_mask);
   1.244 -	dram_assert_ras(RAS2_BIT);
   1.245 +	dram_set_addr(row_addr);
   1.246 +	dram_assert_ras(ras);
   1.247  	/* set column address */
   1.248 -	dram_set_addr(addr & addr_mask);
   1.249 +	dram_set_addr(col_addr);
   1.250  	dram_assert_cas();
   1.251 -	dram_release_ras(RAS2_BIT);
   1.252 +	dram_release_ras(ras);
   1.253  	dram_release_cas();
   1.254  	dram_release_data();
   1.255  	dram_clear_we();
   1.256  }
   1.257  
   1.258 -unsigned char dram_read(unsigned long addr)
   1.259 +unsigned char dram_read(uint32_t addr)
   1.260  {
   1.261  	unsigned char val;
   1.262 +	uint32_t row_addr = (addr >> addr_bits) & addr_mask;
   1.263 +	uint32_t col_addr = addr & addr_mask;
   1.264 +	unsigned char ras = (addr >> (addr_bits * 2)) ? RAS3_BIT : RAS2_BIT;
   1.265  
   1.266  	dram_clear_we();
   1.267 +	/* this is necessary to remove previous data from the lines when no-one is driving them
   1.268 +	 * in case we're trying to detect the presence of a RAS line which doesn't exist
   1.269 +	 */
   1.270 +	dram_set_data(0);
   1.271  	dram_release_data();
   1.272  
   1.273  	/* set row address */
   1.274 -	dram_set_addr((addr >> addr_bits) & addr_mask);
   1.275 -	dram_assert_ras(RAS2_BIT);
   1.276 +	dram_set_addr(row_addr);
   1.277 +	dram_assert_ras(ras);
   1.278  	/* set column address */
   1.279 -	dram_set_addr(addr & addr_mask);
   1.280 +	dram_set_addr(col_addr);
   1.281  	dram_assert_cas();
   1.282  
   1.283  	val = PINA;
   1.284  
   1.285 -	dram_release_ras(RAS2_BIT);
   1.286 +	dram_release_ras(ras);
   1.287  	dram_release_cas();
   1.288  
   1.289  	return val;