main nor.c
  1#include "genesis.h"
  2#include <stdlib.h>
  3#include <string.h>
  4#include "util.h"
  5
  6enum {
  7	NOR_NORMAL,
  8	NOR_PRODUCTID,
  9	NOR_BOOTBLOCK
 10};
 11
 12enum {
 13	NOR_CMD_IDLE,
 14	NOR_CMD_AA,
 15	NOR_CMD_55
 16};
 17
 18//Technically this value shoudl be slightly different between NTSC and PAL
 19//as it's defined as 200 micro-seconds, not in clock cycles
 20#define NOR_WRITE_PAUSE 10690 
 21
 22void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags)
 23{
 24	state->buffer = buffer;
 25	state->page_buffer = malloc(page_size);
 26	memset(state->page_buffer, 0xFF, page_size);
 27	state->size = size;
 28	state->page_size = page_size;
 29	state->product_id = product_id;
 30	state->last_write_cycle = 0xFFFFFFFF;
 31	state->mode = NOR_NORMAL;
 32	state->cmd_state = NOR_CMD_IDLE;
 33	state->alt_cmd = 0;
 34	state->bus_flags = bus_flags;
 35	state->cmd_address1 = 0x5555;
 36	state->cmd_address2 = 0x2AAA;
 37}
 38
 39void nor_run(nor_state *state, m68k_context *m68k, uint32_t cycle)
 40{
 41	if (state->last_write_cycle == 0xFFFFFFFF) {
 42		return;
 43	}
 44	if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) {
 45		state->last_write_cycle = 0xFFFFFFFF;
 46		for (uint32_t i = 0; i < state->page_size; i++) {
 47			state->buffer[state->current_page + i] = state->page_buffer[i];
 48		}
 49		memset(state->page_buffer, 0xFF, state->page_size);
 50		if (state->bus_flags == RAM_FLAG_BOTH) {
 51			//TODO: add base address of NOR device to start and end addresses
 52			m68k_invalidate_code_range(m68k, state->current_page, state->current_page + state->page_size);
 53		}
 54	}
 55}
 56
 57uint8_t nor_flash_read_b(uint32_t address, void *vcontext)
 58{
 59	m68k_context *m68k = vcontext;
 60	genesis_context *gen = m68k->system;
 61	nor_state *state = &gen->nor;
 62	if (
 63		((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
 64		(!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
 65	) {
 66		return 0xFF;
 67	}
 68	if (state->bus_flags != RAM_FLAG_BOTH) {
 69		address = address >> 1;
 70	}
 71	
 72	nor_run(state, m68k, m68k->current_cycle);
 73	switch (state->mode)
 74	{
 75	case NOR_NORMAL:
 76		if (state->bus_flags == RAM_FLAG_BOTH) {
 77			address ^= 1;
 78		}
 79		return state->buffer[address & (state->size-1)];
 80		break;
 81	case NOR_PRODUCTID:
 82		switch (address & (state->size - 1))
 83		{
 84		case 0:
 85			return state->product_id >> 8;
 86		case 1:
 87			return state->product_id;
 88		case 2:
 89			//TODO: Implement boot block protection
 90			return 0xFE;
 91		default:
 92			return 0xFE;
 93		}			//HERE
 94		break;
 95	case NOR_BOOTBLOCK:
 96		break;
 97	}
 98	return 0xFF;
 99}
100
101uint16_t nor_flash_read_w(uint32_t address, void *context)
102{
103	uint16_t value = nor_flash_read_b(address, context) << 8;
104	value |= nor_flash_read_b(address+1, context);
105	return value;
106}
107
108void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle)
109{
110	switch(state->mode)
111	{
112	case NOR_NORMAL:
113		if (state->last_write_cycle != 0xFFFFFFFF) {
114			state->current_page = address & (state->size - 1) & ~(state->page_size - 1);
115		}
116		if (state->bus_flags == RAM_FLAG_BOTH) {
117			address ^= 1;
118		}
119		state->page_buffer[address & (state->page_size - 1)] = value;
120		break;
121	case NOR_PRODUCTID:
122		break;
123	case NOR_BOOTBLOCK:
124		//TODO: Implement boot block protection
125		state->mode = NOR_NORMAL;
126		break;
127	}
128}
129
130void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value)
131{
132	m68k_context *m68k = vcontext;
133	genesis_context *gen = m68k->system;
134	nor_state *state = &gen->nor;
135	if (
136		((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
137		(!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
138	) {
139		return vcontext;
140	}
141	if (state->bus_flags != RAM_FLAG_BOTH) {
142		address = address >> 1;
143	}
144	
145	nor_run(state, m68k, m68k->current_cycle);
146	switch (state->cmd_state)
147	{
148	case NOR_CMD_IDLE:
149		if (value == 0xAA && (address & (state->size - 1)) == state->cmd_address1) {
150			state->cmd_state = NOR_CMD_AA;
151		} else {
152			nor_write_byte(state, address, value, m68k->current_cycle);
153			state->cmd_state = NOR_CMD_IDLE;
154		}
155		break;
156	case NOR_CMD_AA:
157		if (value == 0x55 && (address & (state->size - 1)) == state->cmd_address2) {
158			state->cmd_state = NOR_CMD_55;
159		} else {
160			nor_write_byte(state, state->cmd_address1, 0xAA, m68k->current_cycle);
161			nor_write_byte(state, address, value, m68k->current_cycle);
162			state->cmd_state = NOR_CMD_IDLE;
163		}
164		break;
165	case NOR_CMD_55:
166		if ((address & (state->size - 1)) == state->cmd_address1) {
167			if (state->alt_cmd) {
168				switch(value)
169				{
170				case 0x10:
171					puts("UNIMPLEMENTED: NOR flash erase");
172					break;
173				case 0x20:
174					puts("UNIMPLEMENTED: NOR flash disable protection");
175					break;
176				case 0x40:
177					state->mode = NOR_BOOTBLOCK;
178					break;
179				case 0x60:
180					state->mode = NOR_PRODUCTID;
181					break;
182				}
183			} else {
184				switch(value)
185				{
186				case 0x80:
187					state->alt_cmd = 1;
188					break;
189				case 0x90:
190					state->mode = NOR_PRODUCTID;
191					break;
192				case 0xA0:
193					puts("UNIMPLEMENTED: NOR flash enable protection");
194					break;
195				case 0xF0:
196					state->mode = NOR_NORMAL;
197					break;
198				default:
199					printf("Unrecognized unshifted NOR flash command %X\n", value);
200				}
201			}
202		} else {
203			nor_write_byte(state, state->cmd_address1, 0xAA, m68k->current_cycle);
204			nor_write_byte(state, state->cmd_address2, 0x55, m68k->current_cycle);
205			nor_write_byte(state, address, value, m68k->current_cycle);
206		}
207		state->cmd_state = NOR_CMD_IDLE;
208		break;
209	}
210	return vcontext;
211}
212
213void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value)
214{
215	nor_flash_write_b(address, vcontext, value >> 8);
216	return nor_flash_write_b(address + 1, vcontext, value);
217}