avr_mdcart_sram_lite

annotate main.c @ 6:ff8af8351282

works
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Mar 2017 23:43:41 +0200
parents abb348704dec
children f14e14abe14c
rev   line source
nuclear@3 1 /*
nuclear@5 2 Megadrive USB development cartridge prototype
nuclear@3 3 Copyright (C) 2017 John Tsiombikas <nuclear@member.fsf.org>
nuclear@3 4
nuclear@3 5 This program is free software: you can redistribute it and/or modify
nuclear@3 6 it under the terms of the GNU General Public License as published by
nuclear@3 7 the Free Software Foundation, either version 3 of the License, or
nuclear@3 8 (at your option) any later version.
nuclear@3 9
nuclear@3 10 This program is distributed in the hope that it will be useful,
nuclear@3 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@3 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@3 13 GNU General Public License for more details.
nuclear@3 14
nuclear@3 15 You should have received a copy of the GNU General Public License
nuclear@3 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@3 17 */
nuclear@2 18 #define F_CPU XTAL
nuclear@2 19
nuclear@0 20 #include <stdio.h>
nuclear@1 21 #include <stdlib.h>
nuclear@0 22 #include <string.h>
nuclear@0 23 #include <ctype.h>
nuclear@2 24 #include <stdint.h>
nuclear@0 25 #include <avr/io.h>
nuclear@0 26 #include <avr/interrupt.h>
nuclear@2 27 #include <util/delay.h>
nuclear@0 28 #include "serial.h"
nuclear@0 29
nuclear@1 30 /* pin assignments:
nuclear@5 31 * A[0,7] A0 - A7
nuclear@5 32 * C[0,7] A8 - A15
nuclear@5 33 * D2 A16
nuclear@5 34 * B[0, 7] data
nuclear@5 35 * D4 ~WE
nuclear@5 36 * D5 ~OE
nuclear@5 37 * D7 ~SYS_RESET
nuclear@1 38 */
nuclear@1 39
nuclear@5 40 #define A16_BIT 0x04
nuclear@5 41 #define WE_BIT 0x10
nuclear@5 42 #define OE_BIT 0x20
nuclear@5 43 #define RST_BIT 0x80
nuclear@1 44
nuclear@5 45 #define A16_SHIFT 2
nuclear@1 46
nuclear@5 47 #define MEM_SIZE (128L * 1024L)
nuclear@5 48
nuclear@5 49 #define VER_STR "0.1"
nuclear@5 50
nuclear@5 51 void proc_cmd(char *input);
nuclear@5 52 void run_mode(void);
nuclear@5 53 void prog_mode(void);
nuclear@5 54 void sram_write(uint32_t addr, unsigned char val);
nuclear@5 55 unsigned char sram_read(uint32_t addr);
nuclear@0 56
nuclear@0 57 #define MAX_INPUT_SIZE 128
nuclear@0 58 static char input[MAX_INPUT_SIZE];
nuclear@0 59 static unsigned char inp_cidx;
nuclear@0 60
nuclear@5 61 uint32_t addr;
nuclear@5 62 unsigned char running;
nuclear@5 63 int echo = 0;
nuclear@1 64
nuclear@0 65 int main(void)
nuclear@0 66 {
nuclear@6 67 init_serial(115200);
nuclear@5 68 run_mode();
nuclear@5 69
nuclear@0 70 sei();
nuclear@0 71
nuclear@0 72 for(;;) {
nuclear@2 73 if(have_input()) {
nuclear@0 74 int c = getchar();
nuclear@5 75 if(echo) {
nuclear@5 76 putchar(c);
nuclear@5 77 }
nuclear@0 78
nuclear@0 79 if(c == '\r' || c == '\n') {
nuclear@0 80 input[inp_cidx] = 0;
nuclear@1 81 proc_cmd(input);
nuclear@0 82 inp_cidx = 0;
nuclear@0 83 } else if(inp_cidx < sizeof input - 1) {
nuclear@0 84 input[inp_cidx++] = c;
nuclear@0 85 }
nuclear@0 86 }
nuclear@0 87 }
nuclear@0 88 return 0;
nuclear@0 89 }
nuclear@0 90
nuclear@5 91 void proc_cmd(char *input)
nuclear@0 92 {
nuclear@5 93 char *endp;
nuclear@5 94 int data;
nuclear@5 95
nuclear@5 96 switch(input[0]) {
nuclear@5 97 case 'e':
nuclear@5 98 echo = input[1] == '1' ? 1 : 0;
nuclear@5 99 printf("OK echo %s\n", echo ? "on" : "off");
nuclear@5 100 break;
nuclear@5 101
nuclear@5 102 case 'p':
nuclear@5 103 prog_mode();
nuclear@6 104 puts("OK programming mode");
nuclear@5 105 break;
nuclear@5 106
nuclear@5 107 case 'b':
nuclear@5 108 run_mode();
nuclear@6 109 puts("OK run mode");
nuclear@5 110 break;
nuclear@5 111
nuclear@5 112 case 'a':
nuclear@5 113 addr = strtol(input + 1, &endp, 0);
nuclear@5 114 printf("OK address: %lx\n", (unsigned long)addr);
nuclear@5 115 break;
nuclear@5 116
nuclear@5 117 case 'w':
nuclear@5 118 if(running) {
nuclear@6 119 puts("ERR running");
nuclear@5 120 break;
nuclear@5 121 }
nuclear@5 122 if(addr >= MEM_SIZE) {
nuclear@6 123 puts("ERR overflow");
nuclear@5 124 break;
nuclear@5 125 }
nuclear@5 126
nuclear@5 127 data = strtol(input + 1, &endp, 0);
nuclear@5 128 sram_write(addr++, data);
nuclear@6 129 puts("OK");
nuclear@5 130 break;
nuclear@5 131
nuclear@5 132 case 'r':
nuclear@5 133 if(running) {
nuclear@6 134 puts("ERR running");
nuclear@5 135 break;
nuclear@5 136 }
nuclear@5 137 if(addr >= MEM_SIZE) {
nuclear@6 138 puts("ERR overflow");
nuclear@5 139 break;
nuclear@5 140 }
nuclear@5 141
nuclear@5 142 data = sram_read(addr++);
nuclear@5 143 printf("OK %d\n", (int)data);
nuclear@5 144 break;
nuclear@5 145
nuclear@5 146 default:
nuclear@6 147 puts("ERR unknown command");
nuclear@5 148 break;
nuclear@5 149 }
nuclear@0 150 }
nuclear@1 151
nuclear@5 152 void run_mode(void)
nuclear@1 153 {
nuclear@5 154 /* tri-state everything and release the reset line */
nuclear@6 155 /* do not tri-state WE and keep it high */
nuclear@5 156 DDRA = 0;
nuclear@5 157 PORTA = 0;
nuclear@5 158 DDRB = 0;
nuclear@5 159 PORTB = 0;
nuclear@5 160 DDRC = 0;
nuclear@5 161 PORTC = 0;
nuclear@6 162 DDRD = RST_BIT | WE_BIT;
nuclear@6 163 PORTD = RST_BIT | WE_BIT;
nuclear@2 164
nuclear@5 165 running = 1;
nuclear@1 166 }
nuclear@1 167
nuclear@5 168 void prog_mode(void)
nuclear@5 169 {
nuclear@5 170 /* hold the reset line and take control of the bus */
nuclear@6 171 PORTD = WE_BIT; /* keep WE high to avoid writing random bytes */
nuclear@5 172 DDRD = 0xff;
nuclear@5 173 DDRA = 0xff;
nuclear@5 174 DDRB = 0xff;
nuclear@5 175 DDRC = 0xff;
nuclear@5 176
nuclear@5 177 running = 0;
nuclear@5 178 }
nuclear@5 179
nuclear@5 180 void set_address(uint32_t addr)
nuclear@5 181 {
nuclear@5 182 PORTA = addr & 0xff;
nuclear@5 183 PORTC = (addr >> 8) & 0xff;
nuclear@5 184 PORTD = (PORTD & ~A16_BIT) | ((addr >> (16 - A16_SHIFT)) & A16_BIT);
nuclear@5 185 }
nuclear@5 186
nuclear@5 187 void sram_write(uint32_t addr, unsigned char val)
nuclear@5 188 {
nuclear@5 189 set_address(addr);
nuclear@5 190
nuclear@5 191 /* no need for DDRB change, we drive the bus by default in programming mode */
nuclear@5 192 PORTB = val; /* set data */
nuclear@5 193
nuclear@5 194 /* pulse WE */
nuclear@5 195 PORTD &= ~WE_BIT;
nuclear@5 196 /* WE should be low for at least 9ns, which is way faster than we can toggle it anyway */
nuclear@5 197 PORTD |= WE_BIT;
nuclear@5 198 }
nuclear@5 199
nuclear@5 200 unsigned char sram_read(uint32_t addr)
nuclear@1 201 {
nuclear@1 202 unsigned char val;
nuclear@1 203
nuclear@5 204 set_address(addr);
nuclear@1 205
nuclear@5 206 PORTB = 0; /* make sure we won't read the previously written value */
nuclear@1 207
nuclear@5 208 DDRB = 0; /* release the data bus */
nuclear@5 209 PORTD &= ~OE_BIT; /* assert OE (output enable) */
nuclear@5 210 _delay_us(0.1);
nuclear@5 211 val = PINB; /* read the data */
nuclear@5 212 PORTD |= OE_BIT; /* deassert OE */
nuclear@5 213 DDRB = 0xff; /* take back the bus */
nuclear@1 214
nuclear@1 215 return val;
nuclear@1 216 }