avr_mdcart_sram_lite

diff main.c @ 5:abb348704dec

reads/writes to memory, not tested in the megadrive yet
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Mar 2017 04:27:43 +0200
parents test.c@bd6ad00cb1bc
children ff8af8351282
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/main.c	Sun Mar 12 04:27:43 2017 +0200
     1.3 @@ -0,0 +1,216 @@
     1.4 +/*
     1.5 +Megadrive USB development cartridge prototype
     1.6 +Copyright (C) 2017  John Tsiombikas <nuclear@member.fsf.org>
     1.7 +
     1.8 +This program is free software: you can redistribute it and/or modify
     1.9 +it under the terms of the GNU General Public License as published by
    1.10 +the Free Software Foundation, either version 3 of the License, or
    1.11 +(at your option) any later version.
    1.12 +
    1.13 +This program is distributed in the hope that it will be useful,
    1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.16 +GNU General Public License for more details.
    1.17 +
    1.18 +You should have received a copy of the GNU General Public License
    1.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1.20 +*/
    1.21 +#define F_CPU	XTAL
    1.22 +
    1.23 +#include <stdio.h>
    1.24 +#include <stdlib.h>
    1.25 +#include <string.h>
    1.26 +#include <ctype.h>
    1.27 +#include <stdint.h>
    1.28 +#include <avr/io.h>
    1.29 +#include <avr/interrupt.h>
    1.30 +#include <util/delay.h>
    1.31 +#include "serial.h"
    1.32 +
    1.33 +/* pin assignments:
    1.34 + * A[0,7]	A0 - A7
    1.35 + * C[0,7]	A8 - A15
    1.36 + * D2		A16
    1.37 + * B[0, 7]	data
    1.38 + * D4		~WE
    1.39 + * D5		~OE
    1.40 + * D7		~SYS_RESET
    1.41 + */
    1.42 +
    1.43 +#define A16_BIT	0x04
    1.44 +#define WE_BIT	0x10
    1.45 +#define OE_BIT	0x20
    1.46 +#define RST_BIT	0x80
    1.47 +
    1.48 +#define A16_SHIFT	2
    1.49 +
    1.50 +#define MEM_SIZE	(128L * 1024L)
    1.51 +
    1.52 +#define VER_STR	"0.1"
    1.53 +
    1.54 +void proc_cmd(char *input);
    1.55 +void run_mode(void);
    1.56 +void prog_mode(void);
    1.57 +void sram_write(uint32_t addr, unsigned char val);
    1.58 +unsigned char sram_read(uint32_t addr);
    1.59 +
    1.60 +#define MAX_INPUT_SIZE	128
    1.61 +static char input[MAX_INPUT_SIZE];
    1.62 +static unsigned char inp_cidx;
    1.63 +
    1.64 +uint32_t addr;
    1.65 +unsigned char running;
    1.66 +int echo = 0;
    1.67 +
    1.68 +int main(void)
    1.69 +{
    1.70 +	init_serial(38400);
    1.71 +	run_mode();
    1.72 +
    1.73 +	sei();
    1.74 +
    1.75 +	for(;;) {
    1.76 +		if(have_input()) {
    1.77 +			int c = getchar();
    1.78 +			if(echo) {
    1.79 +				putchar(c);
    1.80 +			}
    1.81 +
    1.82 +			if(c == '\r' || c == '\n') {
    1.83 +				input[inp_cidx] = 0;
    1.84 +				proc_cmd(input);
    1.85 +				inp_cidx = 0;
    1.86 +			} else if(inp_cidx < sizeof input - 1) {
    1.87 +				input[inp_cidx++] = c;
    1.88 +			}
    1.89 +		}
    1.90 +	}
    1.91 +	return 0;
    1.92 +}
    1.93 +
    1.94 +void proc_cmd(char *input)
    1.95 +{
    1.96 +	char *endp;
    1.97 +	int data;
    1.98 +
    1.99 +	switch(input[0]) {
   1.100 +	case 'e':
   1.101 +		echo = input[1] == '1' ? 1 : 0;
   1.102 +		printf("OK echo %s\n", echo ? "on" : "off");
   1.103 +		break;
   1.104 +
   1.105 +	case 'p':
   1.106 +		prog_mode();
   1.107 +		printf("OK programming mode\n");
   1.108 +		break;
   1.109 +
   1.110 +	case 'b':
   1.111 +		run_mode();
   1.112 +		printf("OK boot mode\n");
   1.113 +		break;
   1.114 +
   1.115 +	case 'a':
   1.116 +		addr = strtol(input + 1, &endp, 0);
   1.117 +		printf("OK address: %lx\n", (unsigned long)addr);
   1.118 +		break;
   1.119 +
   1.120 +	case 'w':
   1.121 +		if(running) {
   1.122 +			printf("ERR running\n");
   1.123 +			break;
   1.124 +		}
   1.125 +		if(addr >= MEM_SIZE) {
   1.126 +			printf("ERR overflow\n");
   1.127 +			break;
   1.128 +		}
   1.129 +
   1.130 +		data = strtol(input + 1, &endp, 0);
   1.131 +		sram_write(addr++, data);
   1.132 +		printf("OK %d\n", (int)data);
   1.133 +		break;
   1.134 +
   1.135 +	case 'r':
   1.136 +		if(running) {
   1.137 +			printf("ERR running\n");
   1.138 +			break;
   1.139 +		}
   1.140 +		if(addr >= MEM_SIZE) {
   1.141 +			printf("ERR overflow\n");
   1.142 +			break;
   1.143 +		}
   1.144 +
   1.145 +		data = sram_read(addr++);
   1.146 +		printf("OK %d\n", (int)data);
   1.147 +		break;
   1.148 +
   1.149 +	default:
   1.150 +		printf("ERR unknown command\n");
   1.151 +		break;
   1.152 +	}
   1.153 +}
   1.154 +
   1.155 +void run_mode(void)
   1.156 +{
   1.157 +	/* tri-state everything and release the reset line */
   1.158 +	DDRA = 0;
   1.159 +	PORTA = 0;
   1.160 +	DDRB = 0;
   1.161 +	PORTB = 0;
   1.162 +	DDRC = 0;
   1.163 +	PORTC = 0;
   1.164 +	DDRD = RST_BIT;
   1.165 +	PORTD = RST_BIT;
   1.166 +
   1.167 +	running = 1;
   1.168 +}
   1.169 +
   1.170 +void prog_mode(void)
   1.171 +{
   1.172 +	/* hold the reset line and take control of the bus */
   1.173 +	PORTD = 0;
   1.174 +	DDRD = 0xff;
   1.175 +	DDRA = 0xff;
   1.176 +	DDRB = 0xff;
   1.177 +	DDRC = 0xff;
   1.178 +
   1.179 +	running = 0;
   1.180 +}
   1.181 +
   1.182 +void set_address(uint32_t addr)
   1.183 +{
   1.184 +	PORTA = addr & 0xff;
   1.185 +	PORTC = (addr >> 8) & 0xff;
   1.186 +	PORTD = (PORTD & ~A16_BIT) | ((addr >> (16 - A16_SHIFT)) & A16_BIT);
   1.187 +}
   1.188 +
   1.189 +void sram_write(uint32_t addr, unsigned char val)
   1.190 +{
   1.191 +	set_address(addr);
   1.192 +
   1.193 +	/* no need for DDRB change, we drive the bus by default in programming mode */
   1.194 +	PORTB = val;	/* set data */
   1.195 +
   1.196 +	/* pulse WE */
   1.197 +	PORTD &= ~WE_BIT;
   1.198 +	_delay_us(0.1);
   1.199 +	/* WE should be low for at least 9ns, which is way faster than we can toggle it anyway */
   1.200 +	PORTD |= WE_BIT;
   1.201 +}
   1.202 +
   1.203 +unsigned char sram_read(uint32_t addr)
   1.204 +{
   1.205 +	unsigned char val;
   1.206 +
   1.207 +	set_address(addr);
   1.208 +
   1.209 +	PORTB = 0;			/* make sure we won't read the previously written value */
   1.210 +
   1.211 +	DDRB = 0;			/* release the data bus */
   1.212 +	PORTD &= ~OE_BIT;	/* assert OE (output enable) */
   1.213 +	_delay_us(0.1);
   1.214 +	val = PINB;			/* read the data */
   1.215 +	PORTD |= OE_BIT;	/* deassert OE */
   1.216 +	DDRB = 0xff;		/* take back the bus */
   1.217 +
   1.218 +	return val;
   1.219 +}