Double and long overdue commit..

Various changes to STM8 SWIM code to make more versatile allowing SWIM
pin to be located effectively on any STM32 GPIO pin.  Still haven't
touched an AVR implementation, but made place holders so it can compile
for AVR at least.  These SWIM changes aren't heavily tested, mostly just
made sure could flash SOIC-8 STM8 CIC via CIC CLK.

Beginings of JTAG code to configure CPLDs.  Currently only tested state
change and scan out reading MachXO-256, 4032/64v, & XC9572/36XL CPLDs
Tested and working on inlretro6 v1.0p, stm adapter, & avr kazzos.
Older devices with flipflops will apply 5v signals to JTAG pins but time
is mostly minimized by keeping signals defaulted low unless actively
changing states or scanning data.

Still need to verify scan in working, probably move TDI/TDO long strings
to buffers instead of 32byte PBJE data array.  Also need smarter PBJE
host code to keep track of current state and come up with PBJE register
values without hard coding them..

But things are working fairly well so far with SWIM & JTAG
implementations.  Had some issues where I thought jtag pin toggling was
getting optimized out, but I must have simply had the logic analyzer
speed set too low and was missing pin changes that can be as quick as
40nsec with space optimized code.  Current inl6 code is ~4400Bytes,
without optimization it's nearly 50% larger at ~6550Bytes..!
Optimizations seem fine in testing and with logic analyzer running at
50Mhz which is good because the GPIO registers are set as volatile so
they better not be getting optimized away!
This commit is contained in:
Paul blue asus 2018-01-01 23:32:09 -06:00
parent 535b45be27
commit 3c359ac5ca
21 changed files with 1281 additions and 103 deletions

View File

@ -3,6 +3,10 @@
#include <avr/io.h>
//AVR GPIO ports are 8bits wide
//Use this type when need an int to hold pin mask
#define GPIO_PinMask uint8_t
#define __IO volatile /*!< Defines 'read / write' permissions */
/**

View File

@ -31,6 +31,8 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd
case SNES_INIT: snes_init(); break;
case SWIM_INIT:
return swim_init(operand); break;
case JTAG_INIT:
return jtag_init(operand); break;
case EXP0_PULLUP_TEST:
rdata[RD_LEN] = BYTE_LEN;
@ -210,6 +212,20 @@ uint8_t swim_init( uint8_t swim_lane )
{
switch (swim_lane) {
case SWIM_ON_A0: //Most NES & Famicom carts
//Enable A0 pin on EXT PORT
EXT_A0_ENABLE();
//set A0 to open drain with pull-up enabled
A0_IP_PU();
#ifdef STM_CORE
A0_OD(); //set type to open drain
A0_HI(); //set output high (deasserted)
A0_OP(); //enable as output to have above take effect
#endif
swim_pin = A0;
swim_base = A0bank;
//swim_mask = 1<<A0;
//set set as output high
//define the swim pin, base, & mask
break;
case SWIM_ON_EXP0: //SNES carts
//set to define used by shared_dict_pinport.h
@ -223,7 +239,7 @@ uint8_t swim_init( uint8_t swim_lane )
#endif
swim_pin = EXP0_;
swim_base = EXP0bank;
swim_mask = 1<<EXP0;
//swim_mask = 1<<EXP0;
break;
case SWIM_ON_D0: //NES/FC carts with CICOprocesor
break;
@ -233,6 +249,47 @@ uint8_t swim_init( uint8_t swim_lane )
return SUCCESS;
}
//Initialization of JTAG communications
//the JTAG pin depends on INL board design.
//dict call must provide the "jtag_lane"
//that jtag lane will be used for all subsequent communications.
//if jtag lane is unknown or other problem return error, else return SUCCESS
uint8_t jtag_init( uint8_t jtag_lane )
{
switch (jtag_lane) {
case JTAG_ON_EXP0_3: //Most NES carts
#ifdef STM_INL6
//set base & masks
tdo_base = EXP0bank;
tdo_pin = EXP0;
tdi_base = D8bank;
tdi_pin = D8;
tms_base = D9bank;
tms_pin = D9;
tck_base = D10bank;
tck_pin = D10;
#else
#endif
//enable GPIO banks
//EXT_D8_10_ENABLE(); //EXP0 is also on this GPIO bank
EXP_ENABLE();
CTL_ENABLE(); //not really needed..
//initialize PBJE
jtag_init_pbje();
break;
default:
return ERR_UNKN_JTAG_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

@ -3,6 +3,7 @@
#include "pinport.h"
#include "swim.h"
#include "jtag.h"
#include "shared_dictionaries.h"
#include "shared_errors.h"
@ -12,6 +13,7 @@ void io_reset();
void nes_init();
void snes_init();
uint8_t swim_init(uint8_t opcode);
uint8_t jtag_init(uint8_t opcode);
uint8_t exp0_pullup_test();
#endif

455
firmware/source/jtag.c Normal file
View File

@ -0,0 +1,455 @@
#include "jtag.h"
//=================================================================================================
//
// JTAG operations
// This file includes all the jtag functions possible to be called from the jtag dictionary.
//
// See description of the commands contained here in shared/shared_dictionaries.h
//
//=================================================================================================
//JTAG pin globals initialized by io.c when setting up JTAG port
//Having these as variables allows pins to be easily relocated to any pin
GPIO_TypeDef *tdo_base;
uint8_t tdo_pin;
GPIO_TypeDef *tdi_base;
uint8_t tdi_pin;
GPIO_TypeDef *tms_base;
uint8_t tms_pin;
GPIO_TypeDef *tck_base;
uint8_t tck_pin;
//Paul's Basic JTAG Engine globals
uint8_t pbje_status; //only engine can write, read only by host
uint8_t pbje_command; //only host can write, read only by engine
uint8_t pbje_numclk; //numclk is a sticky value, don't modify!
#define PBJE_DATA_ARRAY_SIZE 32
uint8_t pbje_data[PBJE_DATA_ARRAY_SIZE];
uint8_t pbje_cmd_update_flag;
/* Desc:Function takes an opcode which was transmitted via USB
* then decodes it to call designated function.
* shared_dict_jtag.h is used in both host and fw to ensure opcodes/names align
* Pre: Macros must be defined in firmware pinport.h & jtag.h
* opcode must be defined in shared_dict_jtag.h
* Post:function call complete.
* Rtn: SUCCESS if opcode found, error if opcode not present or other problem.
*/
uint8_t jtag_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata )
{
#define RD_LEN 0
#define RD0 1
#define RD1 2
#define RD2 3
#define RD3 4
#define RD4 5
#define RD5 6
// uint16_t *ret_hword = (uint16_t*) &rdata[1];
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
case PBJE_INIT: jtag_init_pbje(); break;
case GET_CMD: rdata[RD0] = pbje_command;
rdata[RD_LEN] = BYTE_LEN; break;
case GET_STATUS: rdata[RD0] = pbje_status;
rdata[RD_LEN] = BYTE_LEN; break;
case SET_CMD: pbje_command = operand;
//need to immediately update status to overwrite PBJE_DONE from previous command
//signal to main thread that command was updated
//this status is what triggers engine to process current command
pbje_status = PBJE_CMD_RX;
break;
case SET_CMD_WAIT: pbje_command = operand;
pbje_status = PBJE_CMD_RX;
//perform command before returning
jtag_run_pbje();
//return current status
rdata[RD0] = pbje_status;
rdata[RD_LEN] = BYTE_LEN;
break;
case SET_NUMCLK: pbje_numclk = operand; break;
//GET & SET ARRAY DATA
case SET_2B_DATA: pbje_data[0] = operand;
pbje_data[1] = operand>>8;
break;
case GET_6B_DATA: rdata[RD0] = pbje_data[0];
rdata[RD1] = pbje_data[1];
rdata[RD2] = pbje_data[2];
rdata[RD3] = pbje_data[3];
rdata[RD4] = pbje_data[4];
rdata[RD5] = pbje_data[5];
rdata[RD_LEN] = 6;
break;
default:
//opcode doesn't exist
return ERR_UNKN_JTAG_OPCODE;
}
return SUCCESS;
}
void jtag_init_pbje()
{
uint8_t i;
//set outputs to default level
#ifdef STM_INL6
//while these are supposed to be default high, I'm going with low
//these signals aren't 5v tolerant which could be problem with original kazzo boards
TMS_LO();
TDI_LO();
//makes sense for TCK default state to be low as posedge is begining of cycle
TCK_LO();
//enable ouput drivers
TCK_OP();
TCK_PP();
TMS_OP();
TMS_PP();
TDI_OP();
TDI_PP();
#else
exp_byte = 0;
EXP_SET(exp_byte);
#endif
//enable TDO as input
TDO_IP_PU();
//PBJE initialization
//set status & command to INIT
pbje_status = PBJE_INIT;
//only the host writes to command
//pbje_command = PBJE_INIT;
//set NUM_CLK to max this engine can clock based on DATA_ARRAY bit size
pbje_numclk = 0; //byte variable, 0 -> 256
//clear DATA_ARRAY
for( i=0; i<PBJE_DATA_ARRAY_SIZE; i++) {
pbje_data[i] = 0;
}
}
//actual JTAG engine
//called periodically from main thread when jtag engine is on
//this is where the actual JTAG communications are generated
//main thread will call this routine so long as pbje_status != PBJE_OFF
void jtag_run_pbje()
{
//status needs to be CMD_RX to start processing of new command
if (pbje_status == PBJE_CMD_RX) {
//host has issued a command
//process the command and update status accordingly
switch (pbje_command) {
case PBJE_INIT:
jtag_init_pbje();
//status set in function
break;
case PBJE_SHUTDOWN:
pbje_status = PBJE_OFF;
break;
case PBJE_STATE_CHG: //data array holds TMS values to clock values bit packed, TDI undefined
pbje_status = PBJE_PROC;
pbje_state_change( DATA0 );
pbje_status = PBJE_DONE;
break;
case PBJE_TDI_SCAN: //ignore TDO 256max
pbje_status = PBJE_PROC;
pbje_scan( DATA0, 0 );
pbje_status = PBJE_DONE;
break;
case PBJE_TDO_SCAN0: //TDI = 0, TMS=0 256max
pbje_status = PBJE_PROC;
pbje_scan( FORCE0, DATA0 );
pbje_status = PBJE_DONE;
break;
case PBJE_TDO_SCAN1: //TDI = 1, TMS=0 256max
pbje_status = PBJE_PROC;
pbje_scan( FORCE1, DATA0 );
pbje_status = PBJE_DONE;
break;
//case PBJE_HALF_SCAN: //TDI = first half of data array, TDO = second, TMS=0 128max
// pbje_status = PBJE_PROC;
// pbje_scan( DATA0, DATA1 );
// pbje_status = PBJE_DONE;
// break;
case PBJE_FULL_SCAN: //TDI = entire data array, TDO dumped into array stomping TDI, TMS=0 256max
pbje_status = PBJE_PROC;
pbje_scan( DATA0, DATA0 );
pbje_status = PBJE_DONE;
break;
case PBJE_CLOCK0: //data not used, clock TMS=0 for NUMCLK
pbje_status = PBJE_PROC;
pbje_state_change( FORCE0 );
pbje_status = PBJE_DONE;
break;
case PBJE_CLOCK1: //data not used, clock TMS=1 for NUMCLK
pbje_status = PBJE_PROC;
pbje_state_change( FORCE1 );
pbje_status = PBJE_DONE;
break;
//TODO
//case PBJE_FREE_CLOCK0: //data not used, clock TMS=0 indefinely
// pbje_status = PBJE_PROCESSED;
// break;
//case PBJE_FREE_CLOCK1: //data not used, clock TMS=1 indefinely
// pbje_status = PBJE_PROCESSED;
// break;
//case PBJE_LONG_CLOCK0: //data contains 32bit uint for number of clocks, TMS=0, numclk not used
// pbje_status = PBJE_PROCESSED;
// break;
//case PBJE_LONG_CLOCK1: //data contains 32bit uint for number of clocks, TMS=1, numclk not used
// pbje_status = PBJE_PROCESSED;
// break;
default: //unknown command
pbje_status = PBJE_UNKN_CMD;
break;
}
}
}
//change the state of JTAG state machine
//tms data bit packed in data array unless forced 0/1
//numclk contains number of tck clocks to perform
//PRE/POST: TCK is low, all signals low (limit 5v non-tolerance with original kazzos)
void pbje_state_change( uint8_t tms_data )
{
//numclk is a sticky value, don't modify!
uint8_t clk_count = pbje_numclk;
uint8_t cur_byte = 0;
uint8_t cur_bit = 0;
#ifndef STM_INL6
exp_byte = 0;
#endif
//force TMS if not using data array
if( tms_data == FORCE0 ) {
#ifdef STM_INL6
TMS_LO();
#endif
} else if ( tms_data == FORCE1 ) {
#ifdef STM_INL6
TMS_HI();
#else
exp_byte = TMS_MASK;
#endif
}
#ifndef STM_INL6
EXP_SET(exp_byte);
#endif
do{
//if TMS isn't forced, should be in data array
if( tms_data == DATA0 ) {
if( pbje_data[cur_byte] & (1<<cur_bit) ) {
#ifdef STM_INL6
TMS_HI();
#else
exp_byte = TMS_MASK;
#endif
} else {
#ifdef STM_INL6
TMS_LO();
#else
exp_byte = 0;
#endif
}
#ifndef STM_INL6
EXP_SET(exp_byte);
#endif
cur_bit++;
if( cur_bit == 8) {
cur_bit = 0;
cur_byte++;
}
}
//clock in TMS value with rising edge of TCK
#ifdef STM_INL6
TCK_HI();
#else
exp_byte_temp = exp_byte | TCK_MASK;
//need to send macro a single byte variable
EXP_SET(exp_byte_temp);
#endif
//may need to slow between edges.. depending on max TCK frequency...
clk_count--;
//end cycle
#ifdef STM_INL6
TCK_LO();
#else
EXP_SET(exp_byte);
#endif
} while( clk_count != 0x00 ) ;
//restore TMS low
#ifdef STM_INL6
TMS_LO();
#else
EXP_SET(0);
#endif
}
//scan data in & out of JTAG shift register
//tms forced 0 as should be in SHIFT_DR/IR already, leave it there when done
//tdi/tdo data in data array, ingored, or forced 0/1
//numclk contains number of tck clocks to perform
//PRE/POST: TCK is low, all signals low (limit 5v non-tolerance with original kazzos)
void pbje_scan( uint8_t tdi_data, uint8_t tdo_data )
{
//numclk is a sticky value, don't modify!
uint8_t clk_count = pbje_numclk;
uint8_t cur_byte = 0;
uint8_t cur_bit = 0;
//TDO data may stomp over the top of TDI data
//need to temporily save tdi byte before it gets stomped
uint8_t temp_byte = pbje_data[cur_byte];
GPIO_PinMask tdo_read;
//force TMS low to remain in SHIFT-DR/IR state
#ifdef STM_INL6
TMS_LO();
#else
exp_byte = 0;
#endif
//force TDI if not using data array
if( tdi_data == FORCE0 ) {
#ifdef STM_INL6
TDI_LO();
#else
//TDI clear by default
#endif
} else if ( tdi_data == FORCE1 ) {
#ifdef STM_INL6
TDI_HI();
#else
exp_byte |= TDI_MASK;
#endif
}
#ifndef STM_INL6
//output to EXP Flopflop for first time
EXP_SET(exp_byte);
#endif
do {
//if TDI isn't forced, should be in data array
if( tdi_data == DATA0 ) {
if( temp_byte & (1<<cur_bit) ) {
#ifdef STM_INL6
TDI_HI();
#else
exp_byte |= TDI_MASK;
#endif
} else {
#ifdef STM_INL6
TDI_LO();
#else
exp_byte &= ~TDI_MASK;
#endif
}
#ifndef STM_INL6
EXP_SET(exp_byte);
#endif
}
//The first TDO bit should already be shifted out by now
//it actually spit out on falling TCK edge of entering SHIFT-DR/IR
//so it's effectively like we read TDO before TCK rising edge as
//it was shifted out last cycle
//if TDO isn't ignored, need to store in data array
if( tdo_data == DATA0 ) {
//if bit0, clear byte so we only have to set bits
if( cur_bit==0 ) {
pbje_data[cur_byte] = 0;
}
//TDO value should now be shifted out
TDO_RD( tdo_read ); //will be 0 if low, non-zero if high
if( tdo_read ) {
//TDO was set, store it in data array
pbje_data[cur_byte] |= 1<<cur_bit;
}
}
//clock in TMS & TDI value with rising edge of TCK
#ifdef STM_INL6
TCK_HI();
#else
exp_byte_temp = exp_byte | TCK_MASK;
//need to send macro a single byte variable
EXP_SET(exp_byte_temp);
#endif
//may need to slow between edges.. depending on max TCK frequency...
clk_count--;
//end cycle TDO shifted out on falling edge of TCK
#ifdef STM_INL6
TCK_LO();
#else
EXP_SET(exp_byte);
#endif
//increment bit counter
cur_bit++;
if( cur_bit == 8) {
cur_bit = 0;
cur_byte++;
temp_byte = pbje_data[cur_byte];
}
} while( clk_count != 0x00 ) ;
//leave default condition low (better for lack of 5v tolerance)
#ifdef STM_INL6
TDI_LO();
TMS_LO();
#else
EXP_SET(0);
#endif
}

86
firmware/source/jtag.h Normal file
View File

@ -0,0 +1,86 @@
#ifndef _jtag_h
#define _jtag_h
#include "pinport.h"
#include "shared_dictionaries.h"
#include "shared_errors.h"
extern GPIO_TypeDef *tdo_base;
extern uint8_t tdo_pin;
extern GPIO_TypeDef *tdi_base;
extern uint8_t tdi_pin;
extern GPIO_TypeDef *tms_base;
extern uint8_t tms_pin;
extern GPIO_TypeDef *tck_base;
extern uint8_t tck_pin;
//main thread needs access to status to know when engine is running
extern uint8_t pbje_status;
//macros for JTAG signals on pins mcu has direct access to, for now only INL6
#ifdef STM_INL6
//TCK JTAG clock signal
//TMS & TDI latched on rising edges, TDO updated on falling
#define TCK_HI() tck_base->BSRR = 1<<tck_pin
#define TCK_LO() tck_base->BRR = 1<<tck_pin
#define TCK_OP() tck_base->MODER |= (MODER_OP<<(tck_pin*2))
#define TCK_PP() tck_base->OTYPER &= ~(OTYPER_OD<<tck_pin)
//TMS JTAG mode input
#define TMS_HI() tms_base->BSRR = 1<< tms_pin
#define TMS_LO() tms_base->BRR = 1<< tms_pin
#define TMS_OP() tms_base->MODER |= (MODER_OP<<(tms_pin*2))
#define TMS_PP() tms_base->OTYPER &= ~(OTYPER_OD<< tms_pin)
//TDI JTAG data input
#define TDI_HI() tdi_base->BSRR = 1<< tdi_pin
#define TDI_LO() tdi_base->BRR = 1<< tdi_pin
#define TDI_OP() tdi_base->MODER |= (MODER_OP<<(tdi_pin*2))
#define TDI_PP() tdi_base->OTYPER &= ~(OTYPER_OD<< tdi_pin)
//TDI JTAG data output
#define TDO_IP_PU() tdo_base->MODER &= ~(MODER_OP<<(tdo_pin*2)); tdo_base->PUPDR |= (PUPDR_PU<<(tdo_pin*2))
#define TDO_RD(val) val = (tdo_base->IDR & (1<<tdo_pin))
#else //everything else (AVR_KAZZO & STM_ADAPTER)
//EXPANSION PORT SUPPORT
//write only byte wide port
//TDO EXP0 not part of EXP PORT definition (because it's read/write and not behind flipflop)
#define TDO_IP_PU() EXP0_IP_PU()
#define TDO_RD(val) EXP0_RD(val)
//TDI EXP1 (bit 0)
#define TDI_MASK 0x01
//TMS EXP2 (bit 1)
#define TMS_MASK 0x02
//TCK EXP3 (bit 2)
#define TCK_MASK 0x04
//global byte used for byte wide right only EXPANSION port to support devices with EXP flipflops
uint8_t exp_byte;
uint8_t exp_byte_temp;
//signal macros for EXP PORT
#define EXP_ALL_LO() exp_byte = 0x00; EXP_SET(0x00)
#define EXP_ONLY_TMS_HI() exp_byte = TMS_MASK; EXP_SET(TMS_MASK)
#endif //end AVR_KAZZO & STM_ADAPTER
uint8_t jtag_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata );
void jtag_init_pbje();
void jtag_run_pbje();
// false = 0 = ignore
#define FORCE0 0x10 //0x1x -> force
#define FORCE1 0x11
#define DATA0 0x20 //0x2x -> data array
//#define DATA1 0x21
void pbje_state_change( uint8_t tms_data );
void pbje_scan( uint8_t tdi_data, uint8_t tdo_data );
#endif

View File

@ -2,6 +2,7 @@
#include "usb.h"
#include "io.h"
#include "buffer.h"
#include "jtag.h"
#ifdef AVR_CORE
#include <avr/interrupt.h>
@ -86,6 +87,9 @@ int main(void)
//intialize i/o and LED to pullup state
io_reset();
//initialize jtag engine to be off
pbje_status = PBJE_OFF;
//=================
//MAIN LOOP
//=================
@ -112,5 +116,12 @@ int main(void)
//another thought would be to call usbPoll mid programming
//a few times to prevent incoming data from being delayed too long
update_buffers();
//if paul's basic jtag engine "PBJE" is running, main
//thread needs to call engine at periodic intervals to keep it
//running.
if (pbje_status != PBJE_OFF) {
jtag_run_pbje();
}
}
}

View File

@ -12,7 +12,9 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_
#define NOP() do { __asm__ __volatile__ ("nop"); } while (0)
//PIN MACROS
////////////////////////////////
// CONTROL (CTL) PORT PINS
////////////////////////////////
// PC0 "MCO"
#define MCO_IP_PU() CTL_IP_PU(MCObank, MCO)
@ -166,4 +168,35 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_
// PC21 "FCAPU"
////////////////////////////////
// EXTRA (EXT) PORT PINS
////////////////////////////////
// PE0 "A0"
#define A0_IP_PU() EXT_IP_PU(A0bank, A0)
#define A0_IP_FL() EXT_IP_FL(A0bank, A0)
#define A0_OP() EXT_OP(A0bank, A0)
#define A0_LO() EXT_SET_LO(A0bank, A0)
#define A0_HI() EXT_SET_HI(A0bank, A0)
#define A0_RD(val) EXT_RD(A0bank, A0, val)
#ifdef STM_CORE
#define A0_OD() EXT_OD(A0bank, A0)
#define A0_PP() EXT_PP(A0bank, A0)
#endif
// PE1 "D0"
#define D0_IP_PU() EXT_IP_PU(D0bank, D0)
#define D0_IP_FL() EXT_IP_FL(D0bank, D0)
#define D0_OP() EXT_OP(D0bank, D0)
#define D0_LO() EXT_SET_LO(D0bank, D0)
#define D0_HI() EXT_SET_HI(D0bank, D0)
#define D0_RD(val) EXT_RD(D0bank, D0, val)
#ifdef STM_CORE
#define D0_OD() EXT_OD(D0bank, D0)
#define D0_PP() EXT_PP(D0bank, D0)
#endif
#endif //end of file

View File

@ -11,6 +11,9 @@
#include <avr/wdt.h>
#elif STM_CORE
#include <stm32f0xx.h>
//STM32 GPIO ports are effectively 16bits wide
//Use this type when need an int to hold pin mask
#define GPIO_PinMask uint16_t
#endif
//This file contains pinout translations from AVR names to "kazzo" names
@ -1126,5 +1129,156 @@ void software_AXL_CLK();
#endif //AVR_KAZZO or STM_ADAPTER
// ---------------------------------------------------------------------------------------
// EXTRA (EXT) PORT
//
// This port is present on all devices, but all pins aren't necessarily available
// Intention is for pins on this port to act similar to CONTROL PORT, but require
// individual enabling as these pins may conflict with other ports. This is a port
// that allows rules of other ports to be broken. For example a single address pin
// can become bidirectional open drain; which doesn't fit the ADDRESS PORT definition.
// Another use for this would be to establish a SPI port on a few DATA BUS pins.
// Other things that make sense here are serial protocols which need conveinent pin
// macros, but don't make any sense to have individual bit control from host PC.
// The low level protocol is handled from the firmware side since you would never want
// to bit bang these from the host.
//
// Restrictions: Great care must be used when utilizing this port, doing so will often
// break other ports which the pins are shared with. Best to disable this port
// when done with it to then allow the other port to be enabled and initialized.
// Each pin (set) needs it's own enable, the EXT PORT doesn't get enabled with one
// macro since typically only one pin (set) is of interest.
// Directionality: Any allowed, defined separately for each pin
// Driver: Any allowed, defined separately for each pin
// Write/Output: Depends on pins, any allowed
// Read/Input: Depends on pins, any allowed
//
//
// ---------------------------------------------------------------------------------------
#endif
#ifdef STM_INL6
// PE0 "A0" mcupinC0
#define E0bank GPIOC
#define E0 (0U)
// PE1 "D0" mcupinB2
#define E1bank GPIOB
#define E1 (2U)
// PE2 "D8" mcupinB10
#define E2bank GPIOB
#define E2 (10U)
// PE3 "D9" mcupinB11
#define E3bank GPIOB
#define E3 (11U)
// PE4 "D10" mcupinB12
#define E4bank GPIOB
#define E4 (12U)
#endif //STM_INL6
#ifdef STM_ADAPTER
// PE0 "A0" mcupinB2
#define E0bank GPIOB
#define E0 (2U)
// PE1 "D0" mcupinB8
#define E1bank GPIOB
#define E1 (8U)
#define E2nodef
#define E3nodef
#define E4nodef
#endif //STM_ADAPTER
#ifdef AVR_KAZZO
// PE0 "A0" mcupinA0
#define E0bank GPIOA
#define E0 (0U)
// PE1 "D0" mcupinB0
#define E1bank GPIOB
#define E1 (0U)
#define E2nodef
#define E3nodef
#define E4nodef
#endif //AVR_KAZZO
////////////////////////////////////////////////////////////////////////////////
// PORT E pin mappings
////////////////////////////////////////////////////////////////////////////////
//STM8 SWIM PINS A0 & D0 depending on cartridge
#define A0 E0
#define A0bank E0bank
#define D0 E1
#define D0bank E1bank
//JTAG pins for INL6
#ifdef STM_INL6
//TDI
#define D8 E2
#define D8bank E2bank
//TMS
#define D9 E3
#define D9bank E3bank
//TCK
#define D10 E4
#define D10bank E4bank
#endif //JTAG INL6
#ifdef STM_CORE
#define EXT_IP_PU(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR |= (PUPDR_PU<<(pin*2))
#define EXT_IP_FL(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR &= ~(PUPDR_PU<<(pin*2))
#define EXT_OP(bank, pin) bank->MODER |= (MODER_OP<<(pin*2))
#define EXT_OD(bank, pin) bank->OTYPER |= (OTYPER_OD<<(pin)) //open drain has no effect when pin is input
#define EXT_PP(bank, pin) bank->OTYPER &= ~(OTYPER_OD<<(pin))
#define EXT_SET_LO(bank, pin) bank->BRR = 1<<pin
#define EXT_SET_HI(bank, pin) bank->BSRR = 1<<pin
#define EXT_RD(bank, pin, val) val = (bank->IDR & (1<<pin))
//NOTE: STM registers are 16bit "halfwords" so must provide a 16bit val
//each pin needs it's own enable macro
#define EXT_A0_ENABLE() ADDR_EN_CLK() //unnecessarily enables both GPIO banks for STM adapter, oh well
#define EXT_D0_ENABLE() DATA_EN_CLK()
#define EXT_D8_10_ENABLE() DATA_EN_CLK()
#endif //STM_CORE
#ifdef AVR_CORE
#define EXT_IP_PU(bank, pin) bank->DDR &= ~(1<<pin); bank->PORT |= (1<<pin)
#define EXT_IP_FL(bank, pin) bank->DDR &= ~(1<<pin); bank->PORT &= ~(1<<pin)
#define EXT_OP(bank, pin) bank->DDR |= (1<<pin)
#define EXT_SET_LO(bank, pin) bank->PORT &= ~(1<<pin)
#define EXT_SET_HI(bank, pin) bank->PORT |= (1<<pin)
#define EXT_RD(bank, pin, val) val = (uint16_t) (bank->PIN & (1<<pin))
//each pin needs it's own enable macro
#define EXT_A0_ENABLE() //nothing to be done for AVR
#define EXT_D0_ENABLE() //nothing to be done for AVR
#endif //AVR_CORE
#endif //file end

View File

@ -10,13 +10,13 @@
//=================================================================================================
uint8_t swim_pin;
uint16_t swim_mask;
//uint16_t swim_mask;
GPIO_TypeDef *swim_base;
/* 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
* Pre: Macros must be defined in firmware pinport.h & swim.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.
@ -36,7 +36,7 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
case SWIM_SRST:
rdata[RD_LEN] = BYTE_LEN;
//assumes low speed
rdata[RD0] = swim_xfr( 0x0000, ((SWIM_WR<<16) | 4), swim_base, swim_mask); break;
rdata[RD0] = swim_xfr( 0x0000, ((SWIM_WR<<16) | 4), swim_base, 1<<swim_pin); break;
case WOTF:
rdata[RD_LEN] = BYTE_LEN;
rdata[RD0] = swim_wotf( SWIM_LS, operand, miscdata ); break;
@ -64,6 +64,27 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
}
//Doesn't actually delay exact usec, but it's proportional which is good enough for SWIM activation
void delay_us( uint16_t delay )
{
uint16_t i = 0;
delay = delay *4;
//calling and pin toggling overhead is 0.1usec
for( i=0; i<delay; i++) {
NOP();
NOP(); //with delay * 4, and 2x NOP, 10 -> 10.64us, 100 -> 100.62us, 1k -> 1.0001 ms including pin delay
// NOP();
// NOP(); //with delay * 4, adding this NOP, adds 84nsec per delay
//NOP();
//NOP(); //6x NOP, 48Mhz, delay = 10 -> 2.92usec + overhead
}
}
void delay( uint16_t delay )
{
@ -85,43 +106,30 @@ 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
//TODO probably should disable interrupts during this process as they would muck up timing
//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(3*16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
SWIM_SET_LO();
delay_us(16);
SWIM_SET_HI();
//toggle high->low T=1msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 720 = 500.9usec
//TODO move this timed code into a timer to make timing more stable
//between boards, pinport.c code, etc....
#ifdef STM_INL6
delay(3*719);
#endif
#ifdef STM_ADAPTER
delay(3*720);
#endif
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(3*718);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
delay_us(500);
SWIM_SET_LO();
delay_us(500);
SWIM_SET_HI();
}
//toggle high->low T=0.5msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 358 = 256usec
delay(3*356);
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(3*355);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
delay_us(250);
SWIM_SET_LO();
delay_us(250);
SWIM_SET_HI();
}
//pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
//wait for device to take swim_pin low for ~16usec
@ -143,29 +151,28 @@ void swim_activate()
*/
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 very long resets
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(3*16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
SWIM_SET_LO();
delay_us(16);
SWIM_SET_HI();
}
#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" )
#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" )
#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" )
//BSRR 0x18
#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base))
//BRR 0x28
#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base))
//OTYPER 0x04
#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
//#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" )
//#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" )
//#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" )
//
////BSRR 0x18
//#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base))
////BRR 0x28
//#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base))
////OTYPER 0x04
//#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
//#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define NO_RESP 0xFF
#define ACK 0x01
@ -200,7 +207,6 @@ uint16_t append_pairity(uint8_t n)
uint16_t swim_rotf(uint8_t speed, uint16_t addr)
{
uint32_t ack_data = 0;
#ifdef STM_CORE
uint16_t data_pb;
uint32_t spddir_len;
@ -212,26 +218,26 @@ uint16_t swim_rotf(uint8_t speed, uint16_t addr)
// 0b0_0011
data_pb = 0x3000;
spddir_len = ((SWIM_WR|speed)<<16) | 4; //data + pairity ( '0' header not included)
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write N "number of bytes for ROTF"
data_pb = 0x0180;
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @E extended address of write
//always 0x00 since targetting stm8s003 which only has one section
data_pb = 0x0000;
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @H high address of write
data_pb = append_pairity( addr>>8 );
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @L high address of write
@ -239,7 +245,7 @@ uint16_t swim_rotf(uint8_t speed, uint16_t addr)
//this is a read xfr because device will output data immediately after
//writting last byte of command info
spddir_len = ((SWIM_RD|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
//read DATA portion of write
@ -247,7 +253,6 @@ uint16_t swim_rotf(uint8_t speed, uint16_t addr)
//any time NAK is recieved must resend byte
end_swim:
#endif
return ack_data;
@ -256,7 +261,6 @@ end_swim:
uint8_t swim_wotf(uint8_t speed, uint16_t addr, uint8_t data)
{
uint32_t ack_data = 0;
#ifdef STM_CORE
uint16_t data_pb;
uint32_t spddir_len;
//bit sequence:
@ -267,49 +271,58 @@ uint8_t swim_wotf(uint8_t speed, uint16_t addr, uint8_t data)
// 0b0_0101
data_pb = 0x5000;
spddir_len = ((SWIM_WR|speed)<<16) | 4; //data + pairity ( '0' header not included)
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write N "number of bytes for ROTF"
data_pb = 0x0180;
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @E extended address of write
//always 0x00 since targetting stm8s003 which only has one section
data_pb = 0x0000;
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @H high address of write
data_pb = append_pairity( addr>>8 );
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
if (ack_data != ACK) goto end_swim;
//write @L high address of write
data_pb = append_pairity( addr );
//writting last byte of command info
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
//DATA portion of write
data_pb = append_pairity( data );
spddir_len = ((SWIM_WR|speed)<<16) | 9;
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<<swim_pin);
//More bytes can be written
//any time NAK is recieved must resend byte
end_swim:
#endif
return ack_data;
}
#ifdef AVR_CORE
//TODO write assembly function that runs on AVR core....
uint32_t swim_xfr( uint16_t data_pb, uint32_t spddir_len, GPIO_TypeDef *swim_base, uint16_t swim_mask)
{
return 0;
}
#endif
/* Desc:Transfer SWIM bit stream
* Always outputs '0' as first bit for header "from host"
* Will output len number of bits plus one for header

View File

@ -7,7 +7,30 @@
extern uint8_t swim_pin;
extern GPIO_TypeDef *swim_base;
extern uint16_t swim_mask;
//extern uint16_t swim_mask;
//macros
#ifdef STM_CORE
#define SWIM_HI() swim_base->BSRR = 1<<swim_pin
#define SWIM_LO() swim_base->BRR = 1<<swim_pin
#define SWIM_OD() swim_base->OTYPER |= (OTYPER_OD<<swim_pin)
#define SWIM_PP() swim_base->OTYPER &= ~(OTYPER_OD<<swim_pin)
//artificial strong pull-up push pull on posedge, then go back to default open drain
#define SWIM_SET_HI() SWIM_HI();SWIM_OD()
//default is open drain, so going low is simple
#define SWIM_SET_LO() SWIM_LO();SWIM_PP()
#else //AVR_CORE
//TODO AVR SWIM macros here
#define SWIM_HI()
#define SWIM_LO()
#define SWIM_OD()
#define SWIM_PP()
//artificial strong pull-up push pull on posedge, then go back to default open drain
#define SWIM_SET_HI() SWIM_HI();SWIM_OD()
//default is open drain, so going low is simple
#define SWIM_SET_LO() SWIM_LO();SWIM_PP()
#endif
//must match swim.s .equ statements!!!
#define SWIM_RD 0x01
@ -26,6 +49,10 @@ uint8_t swim_wotf(uint8_t speed, uint16_t addr, uint8_t data);
uint16_t append_pairity(uint8_t n);
//assembly functions from swim.s
#ifdef STM_CORE
extern uint32_t swim_xfr( uint16_t data_pb, uint32_t spddir_len, GPIO_TypeDef *swim_base, uint16_t swim_mask);
#else //AVR_CORE
uint32_t swim_xfr( uint16_t data_pb, uint32_t spddir_len, GPIO_TypeDef *swim_base, uint16_t swim_mask);
#endif
#endif

View File

@ -121,6 +121,10 @@ uint16_t usbFunctionSetup(uint8_t data[8]) {
rv[RETURN_ERR_IDX] = swim_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break;
case DICT_JTAG:
rv[RETURN_ERR_IDX] = jtag_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] );
break;
case DICT_BUFFER:
//just give buffer.c the setup packet and let it figure things out for itself

Binary file not shown.

View File

@ -419,6 +419,59 @@ RETURN_DAT_IDX = 4
end
-- external call for jtag dictionary
local function jtag( opcode, operand, misc, data )
if not op_jtag[opcode] then
print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_jtag.h")
return nil
end
if not operand then
operand = 0
elseif type(operand) == "string" then
if not op_jtag[operand] then
print("ERROR undefined operand:", operand, "must be defined in shared_dict_jtag.h")
return nil
end
--decode string operands into
operand = op_jtag[operand]
end
if not misc then misc = 0 end
local wLength, ep = default_rlen_1_in(op_jtag[opcode.."rlen"])
local count
count, data = usb_vend_xfr(
-- ep, dictionary wValue[misc:opcode] wIndex wLength data
ep, dict["DICT_JTAG"], ( misc<<8 | op_jtag[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 )
@ -594,6 +647,7 @@ op_operation = {}
op_nes = {}
op_snes = {}
op_swim = {}
op_jtag = {}
err_codes = {}
-- Dictionary table definitions initialized by calling parser
@ -606,6 +660,7 @@ 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( op_jtag, "../shared/shared_dict_jtag.h")
create_dict_tables( err_codes, "../shared/shared_errors.h")
-- functions other modules are able to call
@ -614,6 +669,7 @@ dict.io = io
dict.nes = nes
dict.snes = snes
dict.swim = swim
dict.jtag = jtag
dict.buffer = buffer
dict.buffer_payload_in = buffer_payload_in
dict.buffer_payload_out = buffer_payload_out

143
host/scripts/app/jtag.lua Normal file
View File

@ -0,0 +1,143 @@
-- create the module's table
local jtag = {}
-- import required modules
local dict = require "scripts.app.dict"
-- file constants
-- local functions
local function wait_pbje_done( num_polls, debug )
local status
while( num_polls > 0 ) do
status = dict.jtag("GET_STATUS")
if( status == op_jtag["PBJE_DONE"]) then
if( debug) then print("PBJE done num polls left:", num_polls) end
return true
else
if( debug) then print("PBJE wasn't done, status:", status) end
end
num_polls = num_polls - 1
end
print("JTAG timed out while waiting for PBJE_DONE")
return false
end
local function run_jtag( debug )
dict.io("JTAG_INIT", "JTAG_ON_EXP0_3")
--dict.jtag("SET_3B_DATA", 0x0201, 0x03 )
--print("return data:", dict.jtag("GET_6B_DATA"))
--print(dict.jtag("SET_CMD", "PBJE_STATE_CHG"))
--print(dict.jtag("GET_CMD"))
--print(dict.jtag("GET_STATUS"))
--first put/verify jtag statemachine is in RESET
dict.jtag("SET_2B_DATA", 0xFFFF)
dict.jtag("SET_NUMCLK", 8)
rv = dict.jtag("SET_CMD_WAIT", "PBJE_STATE_CHG")
--verify command was done
if(rv ~= op_jtag["PBJE_DONE"]) then print("error JTAG not done, status: ", rv) end
--by default jtag should be in IDCODE or BYPASS if IDCODE not present
--change to SCAN-DR state
--reset-DRshift c4 m0010
dict.jtag("SET_2B_DATA", 0x0002)
dict.jtag("SET_NUMCLK", 4)
rv = dict.jtag("SET_CMD_WAIT", "PBJE_STATE_CHG")
--verify command was done
if(rv ~= op_jtag["PBJE_DONE"]) then print("error JTAG not done, status: ", rv) end
--scan out 32bit IDCODE while scanning in 1's to TDI
dict.jtag("SET_NUMCLK", 32)
dict.jtag("SET_CMD", "PBJE_TDO_SCAN1")
--verify done before updating PBJE values
jtag.wait_pbje_done( 4, true )
rv = dict.jtag("GET_6B_DATA")
print("return data:", string.format(" %X, ",rv))
if( rv == 0x1281043 ) then
-- Mach XO 256 01281043
-- 4032v (01805043)
-- 4064v (01809043)
--
-- 9536xl
-- //Loading device with 'idcode' instruction.
-- SIR 8 TDI (fe) SMASK (ff) ;
-- SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f9602093) MASK (0fffffff) ;
--
-- 9572xl
-- //Loading device with 'idcode' instruction.
-- SIR 8 TDI (fe) SMASK (ff) ;
-- SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f9604093) MASK (0fffffff) ;
-- test read gives 59604093
print("IDCODE matches MACHXO-256")
else
print("no match for IDCODE")
end
--Mach XO verify ID code
-- ! Check the IDCODE
--
-- ! Shift in IDCODE(0x16) instruction
-- SIR 8 TDI (16);
-- SDR 32 TDI (FFFFFFFF)
-- TDO (01281043)
-- MASK (FFFFFFFF);
-- --change to SCAN-IR state
-- dict.jtag("SET_2B_DATA", 0x0006)
-- dict.jtag("SET_NUMCLK", 5)
-- dict.jtag("SET_CMD", "PBJE_STATE_CHG")
-- --verify done before updating PBJE values
-- jtag.wait_pbje_done( 4, true )
--
-- --scan in IDCODE instruction
-- dict.jtag("SET_2B_DATA", 0x0016)
-- dict.jtag("SET_NUMCLK", 8)
-- dict.jtag("SET_CMD", "PBJE_TDI_SCAN")
-- --verify done before updating PBJE values
-- jtag.wait_pbje_done( 4, true )
--
-- --change to SCAN-DR state
-- --shift-pause c2 m01
-- --IRpause-DRshift c5 m00111
-- --together c7 m001_1101 -> 0x1D
-- dict.jtag("SET_2B_DATA", 0x001D)
-- dict.jtag("SET_NUMCLK", 7)
-- dict.jtag("SET_CMD", "PBJE_STATE_CHG")
-- --verify done before updating PBJE values
-- jtag.wait_pbje_done( 4, true )
--
--
-- --scan out 32bit IDCODE while scanning in 1's to TDI
-- dict.jtag("SET_NUMCLK", 32)
-- dict.jtag("SET_CMD", "PBJE_TDO_SCAN1")
-- --verify done before updating PBJE values
-- jtag.wait_pbje_done( 4, true )
--
-- print("return data:", dict.jtag("GET_6B_DATA"))
end
-- global variables so other modules can use them
-- call functions desired to run when script is called/imported
-- functions other modules are able to call
jtag.wait_pbje_done = wait_pbje_done
jtag.run_jtag = run_jtag
-- return the module's table
return jtag

View File

@ -27,7 +27,8 @@ ECODE.HERR = 0x09
local cur_CSR = 0x00
local SWIM_CSR = 0x7F80
local DEF_MAX_NAK = 8
--local DEF_MAX_NAK = 8
local DEF_MAX_NAK = 12 --8 wasn't enough especially for long strings of 0x00 -> 0xff or vice versa
-- local functions
local function get_key_for_value( t, value )
@ -184,8 +185,15 @@ local function swim_test()
--print("wotf :", dict.swim("WOTF_HS", 0x0000, 0x00))
--high speed now, enable flag with true
-- wotf(0x0000, 0x00, true)
-- rotf(0x0000, true)
rotf(0x0000, true, true)
wotf(0x0000, 0x00, true, true)
rotf(0x0000, true, true)
wotf(0x0000, 0xFF, true, true)
rotf(0x0000, true, true)
wotf(0x0000, 0xA5, true, true)
rotf(0x0000, true, true)
wotf(0x0000, 0xC3, true, true)
rotf(0x0000, true, true)
-- rotf(0x0000, true)
-- rotf(0x0000, true)
-- rotf(0x0000, true)
@ -263,13 +271,13 @@ local function swim_test()
-- lock_flash_eeprom(true)
-- --read it back
print("READ BACK DATA")
local byte_addr = 0x0200
while byte_addr < 0x0280 do
rotf(byte_addr, true, true)
byte_addr = byte_addr + 1
end
-- print("READ BACK DATA")
-- local byte_addr = 0x0200
-- while byte_addr < 0x0280 do
-- rotf(byte_addr, true, true)
--
-- byte_addr = byte_addr + 1
-- end
--test by blinking LED via periph register access
--v2 board has LED on hi_lo_sel PA2
@ -306,10 +314,10 @@ end
local function start( debug )
dict.io("IO_RESET")
--dict.io("IO_RESET")
dict.io("SNES_INIT")
dict.io("SWIM_INIT", "SWIM_ON_EXP0")
--dict.io("SNES_INIT")
--dict.io("SWIM_INIT", "SWIM_ON_EXP0")
dict.swim("SWIM_ACTIVATE")
--holds SWIM pin low for 16usec+ to reset SWIM comms incase of error

View File

@ -13,6 +13,7 @@ function main ()
local erase = require "scripts.app.erase"
local flash = require "scripts.app.flash"
local swim = require "scripts.app.swim"
local jtag = require "scripts.app.jtag"
-- local crc32 = require "scripts.app.crc32"
local rv
@ -40,7 +41,7 @@ function main ()
-- rv = cart.detect(debug)
local force_cart = true
cart_console = "SNES"
cart_console = "NES"
if (force_cart or cart.detect_console(true)) then
if cart_console == "NES" or cart_console == "Famicom" then
@ -67,37 +68,78 @@ function main ()
nes.read_flashID_prgrom_exp0(true)
--try mapper 30 flash ID
--determined all that could about mapper board
--set rom types and sizes
--perform desired operation
jtag.run_jtag()
--FLASHING:
--erase cart
erase.erase_nes( true )
--open file
local file
file = assert(io.open("inltest.bin", "rb"))
--determine if auto-doubling, deinterleaving, etc,
--needs done to make board compatible with rom
--flash cart
flash.flash_nes( file, true )
--close file
assert(file:close())
--DUMPING:
--create new file
local file
file = assert(io.open("dump.bin", "wb"))
--dump cart into file
dump.dump_nes( file, true )
--close file
assert(file:close())
-- --Check for SWIM on A0
-- dict.io("IO_RESET")
--
-- dict.io("SWIM_INIT", "SWIM_ON_A0")
-- if swim.start(true) then
-- --SWIM is now established and running at HIGH SPEED
-- snes_swimcart = false --don't want to use SWIM pin to control flash /OE, use SNES RESET (EXP0) instead
--
-- -- swim.swim_test()
--
-- --swim.write_optn_bytes( true, true ) -- enable ROP, debug
--
-- --check if ROP set, allow clearing ROP and erasing CIC
-- --blindly erase STM8 CIC for now by disabling ROP
-- swim.disable_ROP_erase(true)
--
-- --open CIC file
-- --local cic_file = assert(io.open("stm8_8KB_zero.bin", "rb"))
-- --local cic_file = assert(io.open("stm8_8KB_0xff.bin", "rb"))
-- local cic_file = assert(io.open("stm8_8KB_testpattern.bin", "rb"))
--
-- --write CIC file
-- swim.write_flash( cic_file )
--
-- --close CIC file
-- assert(cic_file:close())
--
-- -- reset STM8 CIC and end SWIM comms to it can execute what we just flashed
-- swim.stop_and_reset()
-- else
-- print("ERROR problem with STM8 CIC")
-- end
--
-- print("done flashing STM8 on A0")
dict.io("IO_RESET")
-- --determined all that could about mapper board
-- --set rom types and sizes
-- --perform desired operation
-- --FLASHING:
-- --erase cart
-- erase.erase_nes( true )
-- --open file
-- local file
-- file = assert(io.open("inltest.bin", "rb"))
-- --determine if auto-doubling, deinterleaving, etc,
-- --needs done to make board compatible with rom
-- --flash cart
-- flash.flash_nes( file, true )
-- --close file
-- assert(file:close())
-- --DUMPING:
-- --create new file
-- local file
-- file = assert(io.open("dump.bin", "wb"))
-- --dump cart into file
-- dump.dump_nes( file, true )
-- --close file
-- assert(file:close())
-- dict.io("IO_RESET")
elseif cart_console == "SNES" then
snes_swimcart = nil

View File

@ -114,6 +114,8 @@ libusb_device_handle * open_usb_device( libusb_context *context, int log_level )
if ( libusb_get_string_descriptor_ascii( handle,
desc.iManufacturer, (unsigned char *)manf, sizeof(manf) ) > LIBUSB_SUCCESS) {
if (log_level>0) printf("manf_ascii: %s\n",manf);
} else {
printf("\nMatching PID/VID found and opened, but unable to communicate to device, verify drivers installed!!!\n\n");
}
}
if (desc.iProduct) {

View File

@ -48,6 +48,16 @@
#define SWIM_ON_EXP0 0x02 //SNES carts
#define SWIM_ON_D0 0x03 //NES discrete CICOprocessor
//JTAG protocol init
//4 wire serial protocol for configuring and communicating to programmable logic device cores
//different INL boards have this signal on different pins or virtual CIC ports
//So initialization must provide pins to perform all subsequent
//communications with
#define JTAG_INIT 4
// don't define 0x00 to protect from forgetting to pass jtag lane
#define JTAG_ON_EXP0_3 0x01 //Most NES carts with CPLDs
//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

60
shared/shared_dict_jtag.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef _shared_dict_jtag_h
#define _shared_dict_jtag_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
//=============================================================================================
//=============================================================================================
// JTAG DICTIONARY
//
// opcodes contained in this dictionary must be implemented in firmware/source/jtag.c
//
//=============================================================================================
//=============================================================================================
//JTAG opcodes
#define GET_CMD 1 //RL=3
#define SET_CMD 2 //command is only writable by host, read only by engine
#define SET_CMD_WAIT 3 //RL=3 returns command status effectively set, perform, and get/return command
//set command and force device to perform command immediately
//should only be used for quick commands like state change, not for long scan in/outs
#define GET_STATUS 4 //RL=3 only the engine can write to status, ready only by host
#define SET_NUMCLK 5 //numclk is only writable by host, read only by engine
#define SET_2B_DATA 7
#define GET_6B_DATA 8 //RL=8
//PBJE Paul's Basic Jtag engine commands & status'
#define PBJE_STATE_CHG 0x01 //data array holds TMS values to clock values bit packed, TDI undefined
#define PBJE_TDI_SCAN 0x02 //ignore TDO 256max
#define PBJE_TDO_SCAN0 0x03 //TDI = 0, TMS=0 256max
#define PBJE_TDO_SCAN1 0x04 //TDI = 1, TMS=0 256max
#define PBJE_HALF_SCAN 0x05 //TDI = first half of data array, TDO = second, TMS=0 128max
#define PBJE_FULL_SCAN 0x06 //TDI = entire data array, TDO dumped into array stomping TDI, TMS=0 256max
#define PBJE_CLOCK0 0x07 //data not used, clock TMS=0 for NUMCLK
#define PBJE_CLOCK1 0x08 //data not used, clock TMS=1 for NUMCLK
#define PBJE_FREE_CLOCK0 0x09 //data not used, clock TMS=0 indefinely
#define PBJE_FREE_CLOCK1 0x0A //data not used, clock TMS=1 indefinely
#define PBJE_LONG_CLOCK0 0x0B //data contains 32bit uint for number of clocks, TMS=0, numclk not used
#define PBJE_LONG_CLOCK1 0x0C //data contains 32bit uint for number of clocks, TMS=1, numclk not used
//Statuses & commands to get to the status
#define PBJE_INIT 0x80
#define PBJE_PROC 0x81
#define PBJE_DONE 0x82
#define PBJE_CMD_RX 0x83
#define PBJE_UNKN_CMD 0xEE
#define PBJE_OFF 0xF0
#define PBJE_SHUTDOWN 0xFF
#endif

View File

@ -112,4 +112,13 @@
//dictionary used to control swim communications
//=============================================================================================
//=============================================================================================
//=============================================================================================
//=============================================================================================
#define DICT_JTAG 9
#include "shared_dict_jtag.h"
//dictionary used to control jtag communications
//=============================================================================================
//=============================================================================================
#endif

View File

@ -10,12 +10,14 @@
#define ERR_UNKN_SWIM_OPCODE 130
#define ERR_UNKN_JTAG_OPCODE 135
#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_JTAG_LANE 152
#define ERR_UNKN_NES_OPCODE 160
//