Have stm devices activating SWIM on SNES STM8 CIC.

AVR not yet working, performing low level SWIM operations will require
decent amount of core specific code due to differences in pin driver
styles, timers, cycles per instruction, etc.  The fact that SWIM pin
changes based on the board ADDR0, DATA0, EXP0, etc multiplies this low
level code...  Thinking about executing SWIM low level drivers from SRAM.
Initialization could include loading these routines to SRAM.
For now just focusing on supporting SWIM on STM cores for SNES boards.
This commit is contained in:
Paul Molloy 2017-09-02 12:38:56 -05:00
parent 476c28cb24
commit 6eb0570335
16 changed files with 367 additions and 36 deletions

View File

@ -26,9 +26,12 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
case IO_RESET: io_reset(); break;
case NES_INIT: nes_init(); break;
case SNES_INIT: snes_init(); break;
case IO_RESET: io_reset(); break;
case NES_INIT: nes_init(); break;
case SNES_INIT: snes_init(); break;
case SWIM_INIT:
return swim_init(operand); break;
case EXP0_PULLUP_TEST:
rdata[RD_LEN] = BYTE_LEN;
rdata[RD0] = exp0_pullup_test(); break;
@ -196,6 +199,37 @@ void snes_init()
}
//Initialization of SWIM "single wire interface module" communications
//the SWIM pin depends on INL board design.
//dict call must provide the "swim_lane"
//that swim lane will be used for all subsequent communications.
//TODO setup to control SWIM pin as (psuedo) open drain.
//if swim lane is unknown or other problem return error, else return SUCCESS
uint8_t swim_init( uint8_t swim_lane )
{
switch (swim_lane) {
case SWIM_ON_A0: //Most NES & Famicom carts
break;
case SWIM_ON_EXP0: //SNES carts
//set to define used by shared_dict_pinport.h
//that way we can call pinport_call(opcode, null, swim_pin, null)
CTL_ENABLE();
EXP0_IP_PU(); //this enables pullup for stm
#ifdef STM_CORE
EXP0_OD(); //set type to open drain
EXP0_HI(); //set output high (deasserted)
EXP0_OP(); //enable as output to have above take effect
#endif
swim_pin = EXP0_;
break;
case SWIM_ON_D0: //NES/FC carts with CICOprocesor
break;
default:
return ERR_UNKN_SWIM_LANE;
}
return SUCCESS;
}
//Test starts by verifying EXP0 can be driven low, if not, will return one byte of AUX_PIN
//followed by alternating 0xAA, 0x55, 0xAA...
//This test pulls up EXP0 and then reads AUX_PIN 6 times in rapid succession returning error code

View File

@ -2,6 +2,7 @@
#define _io_h
#include "pinport.h"
#include "swim.h"
#include "shared_dictionaries.h"
#include "shared_errors.h"
@ -10,6 +11,7 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd
void io_reset();
void nes_init();
void snes_init();
uint8_t swim_init(uint8_t opcode);
uint8_t exp0_pullup_test();
#endif

View File

@ -192,6 +192,24 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_
default: return ERR_CTL_PIN_NOT_PRESENT;
}
break;
#ifdef STM_CORE
//AVR Doesn't have open drain mode, it must be simulated by
//toggling between input with pullup and output push-pull
case CTL_OD_:
switch ( operand ) {
//currently only defining pins which utilize open drain function
//C8 -> EXP0 (SNES /RESET)
case 8: CTL_OD(C8bank, C8); break;
default: return ERR_CTL_PIN_NOT_PRESENT;
}
break;
case CTL_PP_:
switch ( operand ) {
case 8: CTL_PP(C8bank, C8); break;
default: return ERR_CTL_PIN_NOT_PRESENT;
}
break;
#endif
case CTL_SET_LO_:
switch ( operand ) {
case 0: CTL_SET_LO(C0bank, C0); break;

View File

@ -90,6 +90,11 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_
#define EXP0_HI() CTL_SET_HI(EXP0bank, EXP0)
#define EXP0_RD(val) CTL_RD(EXP0bank, EXP0, val)
#ifdef STM_CORE
#define EXP0_OD() CTL_OD(EXP0bank, EXP0)
#define EXP0_PP() CTL_PP(EXP0bank, EXP0)
#endif
// PC9 "LED"
#define LED_IP_PU() CTL_IP_PU(LEDbank, LED)
#define LED_IP_FL() CTL_IP_FL(LEDbank, LED)

View File

@ -260,6 +260,9 @@ void software_AXL_CLK();
// 1- Open Drain
// N/A when MODER is set to "00" INPUT
// we can generally just ignore this register and use pushpull as AVR does
// but using open drain mode makes things like SWIM much simpler to control
//#define OTYPER_PP 0x00
#define OTYPER_OD 0x01
//
// GPIOx->OSPEEDR[1:0] 32bit registers control pin driver speed/slew
// x0- Low speed (default reset state, except SWD-PA13 default High Spd)
@ -818,6 +821,8 @@ void software_AXL_CLK();
#define CTL_IP_PU(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR |= (PUPDR_PU<<(pin*2))
#define CTL_IP_FL(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR &= ~(PUPDR_PU<<(pin*2))
#define CTL_OP(bank, pin) bank->MODER |= (MODER_OP<<(pin*2))
#define CTL_OD(bank, pin) bank->OTYPER |= (OTYPER_OD<<(pin)) //open drain has no effect when pin is input
#define CTL_PP(bank, pin) bank->OTYPER &= ~(OTYPER_OD<<(pin))
#define CTL_SET_LO(bank, pin) bank->BRR = 1<<pin
#define CTL_SET_HI(bank, pin) bank->BSRR = 1<<pin
#define CTL_RD(bank, pin, val) val = (bank->IDR & (1<<pin))

131
firmware/source/swim.c Normal file
View File

@ -0,0 +1,131 @@
#include "swim.h"
//=================================================================================================
//
// SWIM operations
// This file includes all the swim functions possible to be called from the swim dictionary.
//
// See description of the commands contained here in shared/shared_dictionaries.h
//
//=================================================================================================
/* Desc:Function takes an opcode which was transmitted via USB
* then decodes it to call designated function.
* shared_dict_swim.h is used in both host and fw to ensure opcodes/names align
* Pre: Macros must be defined in firmware pinport.h
* opcode must be defined in shared_dict_swim.h
* Post:function call complete.
* Rtn: SUCCESS if opcode found, error if opcode not present or other problem.
*/
uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata )
{
#define RD_LEN 0
#define RD0 1
#define RD1 2
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
case SWIM_ACTIVATE: swim_activate(); break;
case SWIM_RESET: swim_reset(); break;
// case SWIM_SRST: swim_srst(); break;
// case WOTF: swim_woft(operand); break;
// case ROTF:
// rdata[RD_LEN] = BYTE_LEN;
// rdata[RD0] = swim_roft(); break;
default:
//opcode doesn't exist
return ERR_UNKN_SWIM_OPCODE;
}
return SUCCESS;
}
uint8_t swim_pin;
void delay( uint16_t delay )
{
uint16_t i = 0;
for( i=0; i<delay; i++) {
NOP();
NOP();
} //16->11.8 on stmad
}
/* Desc:Initiate SWIM activate sequence
* Pre: swim_pin must be set and initialized via io.h
* Post:STM8 mcu SWIM active
* Rtn: SUCCESS if able to enter sucessfully.
*/
void swim_activate()
{
uint16_t i;
// pinport_call( CTL_OP_, 0, swim_pin, 0);
//toggles in this manner take 4.55-4.6usec on AVR
//toggles in this manner take 4.9-4.95usec on STM adapter
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
//toggle high->low T=1msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 720 = 500.9usec
#ifdef STM_INL6
delay(719);
#endif
#ifdef STM_ADAPTER
delay(720);
#endif
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(718);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//toggle high->low T=0.5msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 358 = 256usec
delay(356);
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(355);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
//wait for device to take swim_pin low for ~16usec
//it's low for 128 SWIM clock sync pulse
//Best way to do this would be to wait for an interrupt
//on the swim pin going low, then have the isr count
//low time. If anything takes too long timeout.
//TODO
//return SUCCESS/FAIL depending on wether that ~16usec pulse was obtained
// return SUCCESS;
}
/* Desc:Hold swim pin low for >128 SWIM clocks (16usec)
* Pre: swim must be activated by
* Post:STM8 mcu SWIM comms are reset
* Rtn: SUCCESS if device responds with sync window.
*/
void swim_reset()
{
pinport_call( CTL_OP_, 0, swim_pin, 0);
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
}

14
firmware/source/swim.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _swim_h
#define _swim_h
#include "pinport.h"
#include "shared_dictionaries.h"
#include "shared_errors.h"
extern uint8_t swim_pin;
uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata );
void swim_activate();
void swim_reset();
#endif

View File

@ -103,19 +103,23 @@ uint16_t usbFunctionSetup(uint8_t data[8]) {
switch(spacket->bRequest) {
case DICT_PINPORT:
rv[RETURN_ERR_IDX] = pinport_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break; //end of PINPORT
break;
case DICT_IO:
rv[RETURN_ERR_IDX] = io_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break; //end of IO
break;
case DICT_NES:
rv[RETURN_ERR_IDX] = nes_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break; //end of NES
break;
case DICT_SNES:
rv[RETURN_ERR_IDX] = snes_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break; //end of NES
break;
case DICT_SWIM:
rv[RETURN_ERR_IDX] = swim_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break;
case DICT_BUFFER:

View File

@ -17,6 +17,7 @@
#include "nes.h"
#include "snes.h"
#include "buffer.h"
#include "swim.h"
#include "types.h"
#include "shared_usb.h"
#include "shared_errors.h"

View File

@ -194,10 +194,7 @@ local function pinport( opcode, operand, misc, data )
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
-- end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -240,18 +237,14 @@ local function io( opcode, operand, misc, data )
count, data = usb_vend_xfr(
-- ep, dictionary wValue[misc:opcode] wIndex wLength data
ep, dict["DICT_IO"], ( misc<<8 | op_io[opcode]), operand, wLength, data)
--print(count)
local error_code, data_len
if ep == USB_IN then
error_code = data:byte(RETURN_ERR_IDX)
data_len = data:byte(RETURN_LEN_IDX)
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
-- end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -302,10 +295,7 @@ local function nes( opcode, operand, misc, data )
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
--end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -357,10 +347,7 @@ local function snes( opcode, operand, misc, data )
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
--end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -376,6 +363,58 @@ local function snes( opcode, operand, misc, data )
end
-- external call for swim dictionary
local function swim( opcode, operand, misc, data )
if not op_swim[opcode] then
print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_swim.h")
return nil
end
if not operand then
operand = 0
elseif type(operand) == "string" then
if not op_swim[operand] then
print("ERROR undefined operand:", operand, "must be defined in shared_dict_swim.h")
return nil
end
--decode string operands into
operand = op_swim[operand]
end
if not misc then misc = 0 end
local wLength, ep = default_rlen_1_in(op_swim[opcode.."rlen"])
local count
count, data = usb_vend_xfr(
-- ep, dictionary wValue[misc:opcode] wIndex wLength data
ep, dict["DICT_SWIM"], ( misc<<8 | op_swim[opcode]), operand, wLength, data)
--print(count)
local error_code, data_len
if ep == USB_IN then
error_code = data:byte(RETURN_ERR_IDX)
data_len = data:byte(RETURN_LEN_IDX)
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
end
--process the return data string and return it to calling function
if data_len then
return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len)
else
return nil
end
end
local function buffer_payload_in( wLength, buff_num )
local opcode = nil
@ -471,10 +510,7 @@ local function buffer( opcode, operand, misc, data, stringout )
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
-- end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -527,10 +563,7 @@ local function operation( opcode, operand, misc, data )
end
--print("error:", error_code, "data_len:", data_len)
assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code)
--if error_code ~= err_codes["SUCCESS"] then
-- print("ERROR!!! device error code:", error_code)
-- end
assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code)
if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then
print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX)
@ -555,6 +588,7 @@ op_io = {}
op_operation = {}
op_nes = {}
op_snes = {}
op_swim = {}
err_codes = {}
-- Dictionary table definitions initialized by calling parser
@ -566,6 +600,7 @@ create_dict_tables( op_io, "../shared/shared_dict_io.h")
create_dict_tables( op_operation, "../shared/shared_dict_operation.h")
create_dict_tables( op_nes, "../shared/shared_dict_nes.h")
create_dict_tables( op_snes, "../shared/shared_dict_snes.h")
create_dict_tables( op_swim, "../shared/shared_dict_swim.h")
create_dict_tables( err_codes, "../shared/shared_errors.h")
-- functions other modules are able to call
@ -573,6 +608,7 @@ dict.pinport = pinport
dict.io = io
dict.nes = nes
dict.snes = snes
dict.swim = swim
dict.buffer = buffer
dict.buffer_payload_in = buffer_payload_in
dict.buffer_payload_out = buffer_payload_out

View File

@ -31,11 +31,26 @@ function main ()
end
-- print(dict.io("EXP0_PULLUP_TEST"))
--
dict.io("IO_RESET")
dict.io("SNES_INIT")
dict.io("SWIM_INIT", "SWIM_ON_EXP0")
dict.swim("SWIM_ACTIVATE")
--write 0A0h to SWIM_CSR
--bit 5: allows entire memory range to be read & swim reset to be accessed
--bit 7: masks internal reset sources (like WDT..?)
-- dict.swim("WOTF", 0xA0)
dict.io("IO_RESET")
-- debug = true
-- rv = cart.detect(debug)
if cart.detect_console(true) then
local force_cart = true
if (force_cart or cart.detect_console(true)) then
if cart_console == "NES" or cart_console == "Famicom" then
dict.io("IO_RESET")
dict.io("NES_INIT")
@ -95,6 +110,7 @@ function main ()
dict.io("IO_RESET")
dict.io("SNES_INIT")
--SNES detect HiROM or LoROM
--nes.detect_mapper_mirroring(true)
local snes_mapping = "LOROM"
@ -107,7 +123,7 @@ function main ()
--FLASHING:
--erase cart
-- erase.erase_snes( false )
-- erase.erase_snes( false )
--open file
local file
file = assert(io.open("flash.bin", "rb"))
@ -130,7 +146,7 @@ function main ()
--trick to do this at end while debugging so don't have to wait for it before starting
erase.erase_snes( false )
-- erase.erase_snes( false )
dict.io("IO_RESET")

View File

@ -36,6 +36,18 @@
//reset high disables SRAM and puts INL carts in PRGM mode
#define SNES_INIT 2
//SWIM protocol init
//"single wire interface module"
//different INL boards have this signal on different pins
//So initialization must provide pin to perform all subsequent
//communications with
#define SWIM_INIT 3
// don't define 0x00 to protect from forgetting to pass swim lane
#define SWIM_ON_A0 0x01 //NES & Famicom carts
#define SWIM_ON_EXP0 0x02 //SNES carts
#define SWIM_ON_D0 0x03 //NES discrete CICOprocessor
//Test EXP0 drive with pull up
//This is an important test if reling on pulling up EXP0 pin to drive the cart's pin.
//EXP0 is used for various things and may have pull up/down of it's own or significant load

View File

@ -50,6 +50,8 @@
#define CTL_SET_LO_ 4
#define CTL_SET_HI_ 5
#define CTL_RD_ 6 //RL=4 (error code, data length, LSB, MSB)
#define CTL_OD_ 24
#define CTL_PP_ 25
//operands
// PC0 "MCO" mcu clock out M2/phi2, Sysclk, etc
#define C0_ 0

39
shared/shared_dict_swim.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef _shared_dict_swim_h
#define _shared_dict_swim_h
//define dictionary's reference number in the shared_dictionaries.h file
//then include this dictionary file in shared_dictionaries.h
//The dictionary number is literally used as usb transfer request field
//the opcodes and operands in this dictionary are fed directly into usb setup packet's wValue wIndex fields
//=============================================================================================
//=============================================================================================
// SWIM DICTIONARY
//
// opcodes contained in this dictionary must be implemented in firmware/source/swim.c
//
//=============================================================================================
//=============================================================================================
//activate swim on device as initiated with dict_io SWIM_INIT
//return SUCCESS if device responds with sync frame
#define SWIM_ACTIVATE 0
//hold swim pin low for 128 clocks to init comms
//return SUCCESS if device responds with sync frame
#define SWIM_RESET 1
//SWIM commands
#define SWIM_SRST 2 //reset device
#define ROTF 0x11 //read on the fly only one byte
//#define ROTF_8B 0x18 //read on the fly RL=8
//#define ROTF_128B 0x1F //read on the fly RL=128 (current max due to 254B limit)
#define WOTF 0x21 //write on the fly only one byte
//#define WOTF_8B 0x28 //write 8Bytes on the fly
//#define WOTF_128B 0x2F //write 128Bytes on the fly
#endif

View File

@ -103,4 +103,13 @@
//dictionary used to initialize and control operation_info variables
//=============================================================================================
//=============================================================================================
//=============================================================================================
//=============================================================================================
#define DICT_SWIM 8
#include "shared_dict_swim.h"
//dictionary used to control swim communications
//=============================================================================================
//=============================================================================================
#endif

View File

@ -8,11 +8,14 @@
//greater than 128 are possible avr return codes
#define ERR_UNKN_DICTIONARY 128
#define ERR_UNKN_SWIM_OPCODE 130
#define ERR_UNKN_PP_OPCODE 140
#define ERR_CTL_PIN_NOT_PRESENT 141
#define ERR_UNKN_IO_OPCODE 150
#define ERR_UNKN_SWIM_LANE 151
#define ERR_UNKN_NES_OPCODE 160
//