# HG changeset patch # User John Tsiombikas # Date 1488956719 -7200 # Node ID 318a758ede823de15afe508708976a7abe095819 # Parent c47d05df066750ca61f7c59af6795baa43c8b747 ops diff -r c47d05df0667 -r 318a758ede82 Makefile --- a/Makefile Tue Mar 07 23:50:45 2017 +0200 +++ b/Makefile Wed Mar 08 09:05:19 2017 +0200 @@ -1,6 +1,6 @@ src = $(wildcard *.c) obj = $(src:.c=.o) -bin = test_ftdi +bin = test_simm72_dram hex = $(bin).hex eep = $(bin).eep diff -r c47d05df0667 -r 318a758ede82 test.c --- a/test.c Tue Mar 07 23:50:45 2017 +0200 +++ b/test.c Wed Mar 08 09:05:19 2017 +0200 @@ -1,22 +1,63 @@ #include +#include #include #include #include #include #include "serial.h" -void procmd(const char *cmd); +/* pin assignments: + * A[0,7] data + * B[0,7] A0 - A7 + * C[0,3] A8 - A11 + * D7 CAS3 + * D6 RAS2 + * D5 RAS3 + */ + +#define CAS3_BIT 0x80 +#define RAS2_BIT 0x40 +#define RAS3_BIT 0x20 +#define WE_BIT 0x04 + +void proc_cmd(char *cmd); +void cmd_read(char *buf); +void cmd_write(char *buf); +void cmd_setcfg(char *buf); + +void dram_init(void); +void dram_detect(void); +int memtest(unsigned long addr); +void dram_refresh(void); +void dram_write(unsigned long addr, unsigned char val); +unsigned char dram_read(unsigned long addr); #define MAX_INPUT_SIZE 128 static char input[MAX_INPUT_SIZE]; static unsigned char inp_cidx; +/* SIMM access config */ +static int addr_bits; +static unsigned long addr_mask; +static int ras_lines = 1; +static long memsize_kb; /* derived from the above */ + + int main(void) { + dram_init(); init_serial(38400); sei(); - printf("welcome!\n"); + printf("Detecting memory ...\n"); + dram_detect(); + + memsize_kb = (1 << (addr_bits * 2)) * 4 * ras_lines; + + printf("Address lines: %d\n", addr_bits); + printf("RAS lines: %d\n", ras_lines); + printf("Memory size: %ldmb (%ldkb)\n", memsize_kb >> 10, memsize_kb); + fputs("> ", stdout); for(;;) { while(have_input()) { @@ -25,21 +66,265 @@ if(c == '\r' || c == '\n') { input[inp_cidx] = 0; - procmd(input); + proc_cmd(input); inp_cidx = 0; + + fputs("> ", stdout); } else if(inp_cidx < sizeof input - 1) { input[inp_cidx++] = c; } } + + dram_refresh(); + } + return 0; +} + +void proc_cmd(char *cmd) +{ + switch(cmd[0]) { + case 'w': + cmd_write(cmd + 1); + break; + + case 'r': + cmd_read(cmd + 1); + break; + + case 's': + cmd_setcfg(cmd + 1); + break; + + case 'h': + printf("commands:\n"); + printf(" w - write byte to address\n"); + printf(" r - read byte from address\n"); + printf(" s \n"); + printf(" h - help\n"); + break; + } +} + +void cmd_read(char *buf) +{ + char *endp; + unsigned long addr; + unsigned char data; + + addr = strtol(buf, &endp, 0); + if(endp == buf) { + fprintf(stderr, "invalid argument to write command: %s\n", buf); + return; + } + buf = endp; + + data = dram_read(addr); + printf("%04lx: %02x (%u)\n", addr, (unsigned int)data, (unsigned int)data); +} + +void cmd_write(char *buf) +{ + char *endp; + unsigned long addr; + unsigned char data; + + addr = strtol(buf, &endp, 0); + if(endp == buf) { + fprintf(stderr, "invalid address argument to read command: %s\n", buf); + return; + } + buf = endp; + + data = strtol(buf, &endp, 0); + if(endp == buf) { + fprintf(stderr, "invalid data argument to read command: %s\n", buf); + return; + } + buf = endp; + + dram_write(addr, data); + printf("%04lx: %02x (%u)\n", addr, (unsigned int)data, (unsigned int)data); +} + +void cmd_setcfg(char *buf) +{ + char *endp; + char *name, *valstr; + long value; + + name = buf; + while(*name && isspace(*name)) ++name; + if(!*name) { + fprintf(stderr, "invalid or missing variable name\n"); + return; + } + endp = name; + while(*endp && !isspace(*endp)) ++endp; + *endp = 0; + + valstr = endp + 1; + value = strtol(valstr, &endp, 0); + if(endp == valstr) { + fprintf(stderr, "invalid or missing variable value: %s\n", valstr); + return; + } + + if(strcmp(name, "addr_bits") == 0) { + if(value > 0 && value <= 12) { + addr_bits = value; + printf("Address bits: %ld\n", value); + } else { + fprintf(stderr, "invalid address bits value: %ld\n", value); + } + } else if(strcmp(name, "ras_lines") == 0) { + if(value > 0 && value <= 2) { + ras_lines = value; + printf("RAS lines: %d\n", ras_lines); + } else { + fprintf(stderr, "invalid RAS lines value: %ld\n", value); + } + } else { + fprintf(stderr, "unknown variable: %s\n", name); + } +} + +void dram_set_data(unsigned char val) +{ + DDRA = 0xff; + PORTA = val; +} + +void dram_release_data(void) +{ + DDRA = 0; + PORTA = 0; +} + +void dram_set_addr(unsigned long addr) +{ + PORTB = addr & 0xff; + PORTC = (addr >> 8) & 3; +} + +void dram_assert_cas(void) +{ + PORTD &= ~CAS3_BIT; +} + +void dram_release_cas(void) +{ + PORTD |= CAS3_BIT; +} + +void dram_assert_ras(unsigned char bits) +{ + PORTD &= ~bits; +} + +void dram_release_ras(unsigned char bits) +{ + PORTD |= bits; +} + +void dram_set_we(void) +{ + PORTD &= ~WE_BIT; +} + +void dram_clear_we(void) +{ + PORTD |= WE_BIT; +} + +void dram_init(void) +{ + DDRA = 0; /* port A is the data bus */ + PORTA = 0; /* no pullups when A is input */ + DDRB = 0xff; /* port B is A0-A7 */ + DDRC = 0xff; /* port C (low nibble) is A8-A11 */ + DDRD = 0xff; /* port D are the control lines CAS/RAS/WR */ + + PORTD = 0xff; /* deassert all control signals */ +} + +void dram_detect(void) +{ + /* detect how many address bits we've got */ + addr_bits = 12; + while(addr_bits > 8) { + printf("addr mask: %lu\n", (unsigned long)((1 << (unsigned long)addr_bits) - 1)); + addr_mask = (1 << (unsigned long)addr_bits) - 1; + if(memtest((1 << ((unsigned long)addr_bits * 2)) - 1) == 0) { + break; + } + --addr_bits; + } + if(addr_bits < 1) { + fprintf(stderr, "Failed to detect DRAM configuration (address lines)...\n"); + return; + } +} + +int memtest(unsigned long addr) +{ + int i; + unsigned char pat[] = { 0xf0, 0x0f, 0xaa, 0x55, 0xc0, 0x30, 0x0c, 0x03 }; + unsigned char val; + + printf("testing address: %lx (a:%d,r:%d)\n", addr, addr_bits, ras_lines); + + for(i=0; i> addr_bits) & addr_mask); + dram_assert_ras(RAS2_BIT); + /* set column address */ + dram_set_addr(addr & addr_mask); + dram_assert_cas(); + dram_release_ras(RAS2_BIT); + dram_release_cas(); + dram_release_data(); + dram_clear_we(); +} + +unsigned char dram_read(unsigned long addr) +{ + unsigned char val; + + dram_clear_we(); + dram_release_data(); + + /* set row address */ + dram_set_addr((addr >> addr_bits) & addr_mask); + dram_assert_ras(RAS2_BIT); + /* set column address */ + dram_set_addr(addr & addr_mask); + dram_assert_cas(); + + val = PINA; + + dram_release_ras(RAS2_BIT); + dram_release_cas(); + + return val; +}