Allsource.fs Source

This is the complete Forth source code for the BluePill Diagnostics-V1.6 : https://sourceforge.net/projects/mecrisp-stellaris-folkdoc/files/bluepill-diagnostics-v1.6.zip/download

\ -----------------------------------------------------------
\ Program Name: 72mhz-f103.fs
\ Copyright 2022  t.porter , licensed under the GPL3
\ For Mecrisp-Stellaris by Matthias Koch
\ Chip: STM32F103
\ Increases the default Mecrisp-Stellaris clock from 8MHz to 72Mhz
\ -----------------------------------------------------------

compiletoflash
: bit ( u -- u ) 1 swap lshift  1-foldable ;	      \ turn a bit position into a binary number.
: RCC_CR_HSEON ( -- x addr ) 16 bit  ;		      \ External High Speed clock  enable
: RCC_CR_HSERDY? ( -- 1|0 ) 17 bit RCC_CR bit@ ;      \ External High Speed clock ready  flag
: RCC_CFGR_PLLMUL<<  ( %bbbb -- x addr ) 18 lshift ;  \ PLL Multiplication Factor
: RCC_CFGR_PPRE1<<  ( %bbb -- x addr ) 8 lshift ;     \ APB Low speed prescaler  APB1
: RCC_CFGR_ADCPRE<<  ( %bb -- x addr ) 14 lshift ;    \ ADC prescaler
: RCC_CFGR_SW<<  ( %bb -- x addr ) 0 lshift ;	      \ System clock Switch
: RCC_CR_PLLON ( -- x addr ) 24 bit ;		      \ PLL enable
: RCC_CR_PLLRDY? ( -- 1|0 ) 25 bit RCC_CR bit@ ;      \ PLL clock ready flag
: RCC_CFGR_PLLSRC ( -- x addr ) 16 bit ;	      \ PLL entry clock source

: 72mhz ( -- )    \ Increase 8Mhz RC clock to 72 MHz via 8MHz Xtal and PLL.
  $12 FLASH_ACR !		 \ two flash mem wait states
  RCC_CR_HSEON RCC_CR bis!	 \ set HSEON, HSE clock is 8 MHz Xtal source for PLL
   begin RCC_CR_HSERDY? until	 \ wait for HSERDY

    RCC_CFGR_PLLSRC		 \ Clock from PREDIV1 selected as PLL input clock
  7 RCC_CFGR_PLLMUL<<		 \ PLL input clock x 9 (8 * 9 = 72)  HCLK = 72 MHz
  4 RCC_CFGR_PPRE1<<		 \ PCLK1 = HCLK/2 = APB Low speed clock (PCLK1) = 36MHz
  2 RCC_CFGR_ADCPRE<<		 \ ADC clock = PCLK2/6
  2 RCC_CFGR_SW<<		 \ Set PLL as system clock
  + + + + RCC_CFGR  !	
  RCC_CR_PLLON RCC_CR bis!	 \ set PLLON
  begin RCC_CR_PLLRDY? until	 \ wait for PLLRDY
;

compiletoram 

72mhz
 
\ Program Name: systick.fs
\ Date: Wed 8 Jan 2022 13:13:57 AEDT
\ Copyright 2022 by t.j.porter ,  licensed under the GPLV3
\ For Mecrisp-Stellaris by Matthias Koch.
\ https://sourceforge.net/projects/mecrisp/
\ Standalone: no preloaded support files required
\ This systick design is based on this article:
\ https://embedded.fm/blog/2016/9/26/scheduling-code-on-bare-metal?rq=systick
\
\ This Program: Interrupt driven STM32Fxxx Systick Timing Library
\
\ Note the (STK) is not a part of STM32F CMSIS-SVD
\ See: ST PM0215 Programming manual, page 85-91
\
\ ---------------------------------------------------------------------------\
 compiletoflash
 \ compiletoram

\ : bit ( u -- u ) 1 swap lshift  1-foldable ;	\ normally in 72mhz-f103.fs
\ : 72mhz ( dummy ) ;
 
  $E000E010   constant stk_csr     \ RW  SysTick control and status  
  $E000E014   constant stk_rvr     \ RW  SysTick reload value 
  $E000E018   constant stk_cvr     \ RW  SysTick current value 
  $E000E01C   constant stk_calib   \ RO  SysTick calibration value 

 0 variable ticktime	\ 32 bits or -> $ffffffff u. = 4294967295 ms, 4294967 seconds,
			\ 71582 minutes, 19.88 Hrs
 
 : tickint ( -- )       \ tickint: sysTick exception request enable
   %010 stk_csr bis!    \ 1 = Counting down to zero asserts the SysTick exception request.
 ;
 
 : systick-handler ( -- )
   1 ticktime +!	\ increment ticktime by 1
 ;
 
 : init.systick	( 0.1 ms cal value -- )	  \ init systick
   stk_rvr !				  \ systick calib for 0.11ms 
   %101 stk_csr bis!			  \ systick enable
   ['] systick-handler irq-systick !	  \ 'hooks' the systick-handler word (above) to the systick interrupt
   tickint
 ;
 
 : ticktime. ( -- )	\ print now time
   ticktime @ .
 ;

 : zero-ticktime ( -- )	\ zero now time
   0 ticktime !
 ;

 : ms.delay ( u -- )	\ accurate  1 millisecond blocking delay, range is 1ms to 19.88 Hrs (32 bytes)
    zero-ticktime
    10 *                \ convert to ms
      begin
	 ticktime @ over u>=
      until
    drop
 ;

 7200 1 - init.systick   \ 72MHz: 7200 = .1ms
 compiletoram
\ Program Name: defcount.fs
\ Date: Fri 02 Oct 2022 
\ Copyright 2022 by Matthias Koch licensed under the GPLV3
\ For Mecrisp-Stellaris by Matthias Koch.
\ https://sourceforge.net/projects/mecrisp/
\ Function: Counts all the Words in teh dictionary

compiletoflash

: defcount ( -- u )
  0
  dictionarystart
  begin
    swap 1+ swap
    dictionarynext
  until
  drop
;

compiletoram
\ Program Name: uptest.fs
\ Date: Fri 02 Oct 2022 
\ Copyright 2022 by t.j.porter , licensed under the GPLV3
\ For Mecrisp-Stellaris by Matthias Koch.
\ https://sourceforge.net/projects/mecrisp/
\ Dependencies: defcount.fs
\ Function: Determine compile speed including upload delays. Source must have all comments and spaces removed.

 compiletoflash

  0 variable old-words		
  0 variable new-words
  0 variable tot-words
  0 variable timestamp	   

 : uptest ( -- print stats )	 \ finish uptest and print stats
   defcount  new-words !
   new-words @ old-words @ - tot-words !
   ticktime @ timestamp !	 \ get current elapsed time
   cr
   ." ------------------- " cr
   ." Upload Speed Stats: " cr
   ." ------------------- " cr
   ." Number of uploaded Words: " tot-words @ . cr
   0 tot-words @     \ convert total words to a fixed point s31.32 number  
   0 timestamp @     \ convert ticktime to a fixed point s31.32 number in 100uS increments
   0 10000 f/  2dup  \ divide ticktime by 10000 to display seconds
   ." Source upload time : " 2 f.n ." seconds " cr
   ." Source upload/compile rate: " f/ 1 f.n  ." Words per second " cr
   ." Hardware: STM32F103C8 @ 75MHz " cr
   ." Everything but source is stripped " cr
   ." Upload method: SWD2" cr
  ;
	
   compiletoram	     
   defcount old-words !	   \ save pre-existing word count for later computation with uptest
   zero-ticktime	   \ start timer ( 100 Microsecond increments )
\ Program Name: utils.fs  for Mecrisp-Stellaris by Matthias Koch and licensed under the GPL
\ Copyright 2022 t.porter  and licensed under the BSD license.
\ This program must be loaded before memmap.fs as it provided the pretty printing legend for generic 32 bit prints
\ Also included is "bin." which prints the binary form of a number with no spaces between numbers for easy copy and pasting purposes

compiletoflash

\ -------------------
\  Beautiful output
\ -------------------

: u.1 ( u -- ) 0 <# # #> type ;
: u.2 ( u -- ) 0 <# # # #> type ;
: u.3 ( u -- ) 0 <# # # # #> type ;
: u.4 ( u -- ) 0 <# # # # # #> type ;
: u.8 ( u -- ) 0 <# # # # # # # # # #> type ;
: h.1 ( u -- ) base @ hex swap  u.1  base ! ;
: h.2 ( u -- ) base @ hex swap  u.2  base ! ;
: h.3 ( u -- ) base @ hex swap  u.3  base ! ;
: h.4 ( u -- ) base @ hex swap  u.4  base ! ;
: h.8 ( u -- ) base @ hex swap  u.8  base ! ;

: hex.1 h.1 ;
: hex.2 h.2 ;
: hex.3 h.3 ;
: hex.4 h.4 ;

: u.ns 0 <# #s #> type ;
: const. ."  #" u.ns ;
: addr. u.8 ;
: .decimal base @ >r decimal . r> base ! ;

: bit ( u -- u ) 1 swap lshift  1-foldable ;	\ turn a bit position into a binary number.

: b8loop. ( %b --  ) \ print  32 bits in 4 bit groups
0 <#
7 0 DO
# # # #
32 HOLD
LOOP
# # # # 
#>
TYPE ;

: b16loop. ( %b --  ) \ print 32 bits in 2 bit groups
0 <#
15 0 DO
# #
32 HOLD
LOOP
# #
#>
TYPE ;

: b16loop-a. ( %b --  ) \ print 16 bits in 1 bit groups
0  <#
15 0 DO 
#
32 HOLD
LOOP
#
#>
TYPE ;

: b32loop. ( %b --  ) \ print 32 bits in 1 bit groups with vertical bars
0  <#
31 0 DO 
# 32 HOLD LOOP
# #>
TYPE ; 

: b32sloop. ( %b --  ) \ print 32 bits in 1 bit groups without vertical bars
0  <#
31 0 DO
# LOOP
# #>
TYPE ;

\ Manual Use Legends ..............................................
: bin. ( x --  )  cr \ 1 bit legend - manual use
." 3322222222221111111111" cr
." 10987654321098765432109876543210 " cr
binary b32sloop. decimal cr ;

: bin1. ( x --  ) cr \ 1 bit legend - manual use
." 3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1|" cr
." 1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0 " cr
binary b32loop. decimal cr ;

: bin2. ( x --  ) cr \ 2 bit legend - manual use
." 15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00 " cr
binary b16loop. decimal cr ;

: bin4. ." Must be bin4h. or bin4l. " cr ;

: bin4l. ( x --  ) cr \ 4 bit generic legend for bits 7 - 0 - manual use
."  07   06   05   04   03   02   01   00  " cr
binary b8loop. decimal cr ;

: bin4h. ( x --  ) cr \ 4 bit generic legend for bits 15 - 8 - manual use
."  15   14   13   12   11   10   09   08  " cr
binary b8loop. decimal cr ;

: bin16. ( x --  ) cr  \ halfword legend
." 1|1|1|1|1|1|" cr
." 5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0 " cr
binary b16loop-a. decimal cr ;

compiletoram
\ File: STM32F103C8T6.gpio.mode.fs 			   
\ Created: Mon  8 Feb 2022 14:09:48 AEDT							   
\ Author 2022 by t.j.porter 	   
\ Purpose: New format for STM32F1 GPIO modes			   
\ MCU: STM32F1xxx								   
\ Board: BluePill							   
\ Core: 								   
\ Required:							   
\ Recommended:							   
\ Based on:							   
\ Literature:							   
\ License: GPL3, please see COPYING
\ Example
\ %0000 constant input.analog     \ input, analog
\ %0001 constant output.pp        \ output, push-pull, 10 mhz
\ %0100 constant input.floating   \ input, floating
\ %0101 constant output.od        \ output, open-drain, 10 mhz
\ %1000 constant input.pullx      \ pulldown ODR = 0 pullup ODR = 1
\ %1001 constant output.af.pp     \ output, alt func, push-pull, 10 mhz
\ %1101 constant output.af.od     \ output, alt func, open-drain, 10 mhz
\ 
\ $40010800 constant GPIOA ( General purpose I/O )
\ GPIOA $0 + constant GPIOA_CRL ( read-write )
\ : GPIOA_MODER0 ( %bbbb -- x addr ) GPIOA_CRL ; \ GPIOA
\ 
\ $F GPIOA_MODER0 BIC!            \ clear all 4 MODER bits first
\ input.pullx GPIOA_MODER0 BIS!   \ Input, pullup/down, ODR-0 is 0 (default) so it has a pull down already
\ 



compiletoflash

\ New Memmap



\ Commented out as this is the full list but only a few are required
\ GPIO Configs, %1100  is reserved
\ STM32F1xx GPIO MODE constants
\ %0000 constant input.a      \ input, analog
\ %0001 constant output.pp.10      \ output, push-pull, 10 mhz 
\ %0010 constant output.pp.2	      \ output, push-pull,  2 mhz 
\ %0011 constant output.pp.50      \ output, push-pull, 50 mhz
\ %0100 constant input.float      \ input, floating
\ %0101 constant output.od.10      \ output, open-drain, 10 mhz
\ %0110 constant output.od.2	      \ output, open-drain,  2 mhz
\ %0111 constant output.od.50      \ output, open-drain, 50 mhz
\ %1000 constant input.pullx      \ input, pullx
\ %1001 constant output.af.pp.10   \ output, alt func, push-pull, 10 mhz
\ %1010 constant output.af.pp.2    \ output, alt func, push-pull,  2 mhz
\ %1011 constant output.af.pp.50   \ output, alt func, push-pull, 50 mhz
\ %1101 constant output.af.od.10   \ output, alt func, open-drain, 10 mhz
\ %1110 constant output.af.od.2    \ output, alt func, open-drain,  2 mhz
\ %1111 constant output.af.od.50   \ output, alt func, open-drain, 50 mhz

\ GPIO Configs
\ These condense into 7 choices
%0000 constant input.analog	 \ input, analog
%0001 constant output.pp	 \ output, push-pull, 10 mhz
%0100 constant input.floating	 \ input, floating
%0101 constant output.od	 \ output, open-drain, 10 mhz
%1000 constant input.pullx	 \ pulldown ODR = 0 pullup ODR = 1 
%1001 constant output.af.pp	 \ output, alt func, push-pull, 10 mhz
%1101 constant output.af.od	 \ output, alt func, open-drain, 10 mhz

: gpio? ( -- ) ." Mode Syntax " cr     \ gpio syntax memory jogger Word
   ." input.analog " cr
   ." output.pp 10mhz " cr
   ." input.floating " cr
   ." output.od 10mhz " cr
   ." input.pullx  pulldown ODR = 0, pullup ODR = 1 " cr
   ." output.af.pp 10mhz " cr
   ." output.af.od 10mhz " cr cr
 ;


\ Choose the following to paste for GPIOA, B and C
\ GPIOA_CRL (read-write) Reset:0x44444444
\  : GPIOA_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOA_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOA_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOA_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOA_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOA_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOA_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOA_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOA_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOA_CRH (read-write) Reset:0x44444444
\  : GPIOA_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOA_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOA_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOA_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOA_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOA_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOA_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOA_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ; 

\ GPIOB_CRL (read-write) Reset:0x44444444
\  : GPIOB_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOB_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOB_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOB_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOB_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOB_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOB_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOB_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOB_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOB_CRH (read-write) Reset:0x44444444
\  : GPIOB_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOB_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOB_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOB_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOB_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOB_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOB_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOB_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ;

\ GPIOC_CRL (read-write) Reset:0x44444444
\  : GPIOC_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOC_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOC_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOC_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOC_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOC_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOC_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOC_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOC_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOC_CRH (read-write) Reset:0x44444444
\  : GPIOC_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOC_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOC_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOC_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOC_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOC_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOC_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOC_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ;

compiletoram
\ TEMPLATE FILE for STM32F103xx
\ reg-print.xsl Copyright Terry Porter 2022 "terry@tjporter.com.au" 
\ GPL3 Licensed 

compiletoflash

: WRITEONLY ( -- ) ." write-only" cr ;

: rcc_cr. cr ." rcc_cr.   $" RCC_CR @ dup hex.  bin1. ;
: rcc_cfgr. cr ." rcc_cfgr.   $" RCC_CFGR @ dup hex.  bin1. ;
: rcc_cir. cr ." rcc_cir.   $" RCC_CIR @ dup hex.  bin1. ;
: rcc_apb2rstr. cr ." rcc_apb2rstr.  RW   $" RCC_APB2RSTR @ dup hex.  bin1. ;
: rcc_apb1rstr. cr ." rcc_apb1rstr.  RW   $" RCC_APB1RSTR @ dup hex.  bin1. ;
: rcc_ahbenr. cr ." rcc_ahbenr.  RW   $" RCC_AHBENR @ dup hex.  bin1. ;
: rcc_apb2enr. cr ." rcc_apb2enr.  RW   $" RCC_APB2ENR @ dup hex.  bin1. ;
: rcc_apb1enr. cr ." rcc_apb1enr.  RW   $" RCC_APB1ENR @ dup hex.  bin1. ;
: rcc_bdcr. cr ." rcc_bdcr.   $" RCC_BDCR @ dup hex.  bin1. ;
: rcc_csr. cr ." rcc_csr.   $" RCC_CSR @ dup hex.  bin1. ;
: rcc.
rcc_cr. 
rcc_cfgr. 
rcc_cir. 
rcc_apb2rstr. 
rcc_apb1rstr. 
rcc_ahbenr. 
rcc_apb2enr. 
rcc_apb1enr. 
rcc_bdcr. 
rcc_csr. 
;

: gpioa_crl. cr ." gpioa_crl.  RW   $" GPIOA_CRL @ dup hex.  bin1. ;
: gpioa_crh. cr ." gpioa_crh.  RW   $" GPIOA_CRH @ dup hex.  bin1. ;
: gpioa_idr. cr ." gpioa_idr.  RO   $" GPIOA_IDR @ dup hex.  bin1. ;
: gpioa_odr. cr ." gpioa_odr.  RW   $" GPIOA_ODR @ dup hex.  bin1. ;
: gpioa_bsrr. cr ." GPIOA_BSRR " WRITEONLY ; 
: gpioa_brr. cr ." GPIOA_BRR " WRITEONLY ; 
: gpioa_lckr. cr ." gpioa_lckr.  RW   $" GPIOA_LCKR @ dup hex.  bin1. ;
: gpioa.
gpioa_crl. 
gpioa_crh. 
gpioa_idr. 
gpioa_odr. 
gpioa_bsrr. 
gpioa_brr. 
gpioa_lckr. 
;

: gpiob_crl. cr ." gpiob_crl.  RW   $" GPIOB_CRL @ dup hex.  bin1. ;
: gpiob_crh. cr ." gpiob_crh.  RW   $" GPIOB_CRH @ dup hex.  bin1. ;
: gpiob_idr. cr ." gpiob_idr.  RO   $" GPIOB_IDR @ dup hex.  bin1. ;
: gpiob_odr. cr ." gpiob_odr.  RW   $" GPIOB_ODR @ dup hex.  bin1. ;
: gpiob_bsrr. cr ." GPIOB_BSRR " WRITEONLY ; 
: gpiob_brr. cr ." GPIOB_BRR " WRITEONLY ; 
: gpiob_lckr. cr ." gpiob_lckr.  RW   $" GPIOB_LCKR @ dup hex.  bin1. ;
: gpiob.
gpiob_crl. 
gpiob_crh. 
gpiob_idr. 
gpiob_odr. 
gpiob_bsrr. 
gpiob_brr. 
gpiob_lckr. 
;

: gpioc_crl. cr ." gpioc_crl.  RW   $" GPIOC_CRL @ dup hex.  bin1. ;
: gpioc_crh. cr ." gpioc_crh.  RW   $" GPIOC_CRH @ dup hex.  bin1. ;
: gpioc_idr. cr ." gpioc_idr.  RO   $" GPIOC_IDR @ dup hex.  bin1. ;
: gpioc_odr. cr ." gpioc_odr.  RW   $" GPIOC_ODR @ dup hex.  bin1. ;
: gpioc_bsrr. cr ." GPIOC_BSRR " WRITEONLY ; 
: gpioc_brr. cr ." GPIOC_BRR " WRITEONLY ; 
: gpioc_lckr. cr ." gpioc_lckr.  RW   $" GPIOC_LCKR @ dup hex.  bin1. ;
: gpioc.
gpioc_crl. 
gpioc_crh. 
gpioc_idr. 
gpioc_odr. 
gpioc_bsrr. 
gpioc_brr. 
gpioc_lckr. 
;

: exti_imr. cr ." exti_imr.  RW   $" EXTI_IMR @ dup hex.  bin1. ;
: exti_emr. cr ." exti_emr.  RW   $" EXTI_EMR @ dup hex.  bin1. ;
: exti_rtsr. cr ." exti_rtsr.  RW   $" EXTI_RTSR @ dup hex.  bin1. ;
: exti_ftsr. cr ." exti_ftsr.  RW   $" EXTI_FTSR @ dup hex.  bin1. ;
: exti_swier. cr ." exti_swier.  RW   $" EXTI_SWIER @ dup hex.  bin1. ;
: exti_pr. cr ." exti_pr.  RW   $" EXTI_PR @ dup hex.  bin1. ;
: exti.
exti_imr. 
exti_emr. 
exti_rtsr. 
exti_ftsr. 
exti_swier. 
exti_pr. 
;

: tim2_cr1. cr ." tim2_cr1.  RW   $" TIM2_CR1 @ dup hex.  bin1. ;
: tim2_cr2. cr ." tim2_cr2.  RW   $" TIM2_CR2 @ dup hex.  bin1. ;
: tim2_smcr. cr ." tim2_smcr.  RW   $" TIM2_SMCR @ dup hex.  bin1. ;
: tim2_dier. cr ." tim2_dier.  RW   $" TIM2_DIER @ dup hex.  bin1. ;
: tim2_sr. cr ." tim2_sr.  RW   $" TIM2_SR @ dup hex.  bin1. ;
: tim2_egr. cr ." TIM2_EGR " WRITEONLY ; 
: tim2_ccmr1_output. cr ." tim2_ccmr1_output.  RW   $" TIM2_CCMR1_Output @ dup hex.  bin1. ;
: tim2_ccmr1_input. cr ." tim2_ccmr1_input.  RW   $" TIM2_CCMR1_Input @ dup hex.  bin1. ;
: tim2_ccmr2_output. cr ." tim2_ccmr2_output.  RW   $" TIM2_CCMR2_Output @ dup hex.  bin1. ;
: tim2_ccmr2_input. cr ." tim2_ccmr2_input.  RW   $" TIM2_CCMR2_Input @ dup hex.  bin1. ;
: tim2_ccer. cr ." tim2_ccer.  RW   $" TIM2_CCER @ dup hex.  bin1. ;
: tim2_cnt. cr ." tim2_cnt.  RW   $" TIM2_CNT @ dup hex.  bin1. ;
: tim2_psc. cr ." tim2_psc.  RW   $" TIM2_PSC @ dup hex.  bin1. ;
: tim2_arr. cr ." tim2_arr.  RW   $" TIM2_ARR @ dup hex.  bin1. ;
: tim2_ccr1. cr ." tim2_ccr1.  RW   $" TIM2_CCR1 @ dup hex.  bin1. ;
: tim2_ccr2. cr ." tim2_ccr2.  RW   $" TIM2_CCR2 @ dup hex.  bin1. ;
: tim2_ccr3. cr ." tim2_ccr3.  RW   $" TIM2_CCR3 @ dup hex.  bin1. ;
: tim2_ccr4. cr ." tim2_ccr4.  RW   $" TIM2_CCR4 @ dup hex.  bin1. ;
: tim2_dcr. cr ." tim2_dcr.  RW   $" TIM2_DCR @ dup hex.  bin1. ;
: tim2_dmar. cr ." tim2_dmar.  RW   $" TIM2_DMAR @ dup hex.  bin1. ;
: tim2.
tim2_cr1. 
tim2_cr2. 
tim2_smcr. 
tim2_dier. 
tim2_sr. 
tim2_egr. 
tim2_ccmr1_output. 
tim2_ccmr1_input. 
tim2_ccmr2_output. 
tim2_ccmr2_input. 
tim2_ccer. 
tim2_cnt. 
tim2_psc. 
tim2_arr. 
tim2_ccr1. 
tim2_ccr2. 
tim2_ccr3. 
tim2_ccr4. 
tim2_dcr. 
tim2_dmar. 
;

: i2c1_cr1. cr ." i2c1_cr1.  RW   $" I2C1_CR1 @ dup hex.  bin1. ;
: i2c1_cr2. cr ." i2c1_cr2.  RW   $" I2C1_CR2 @ dup hex.  bin1. ;
: i2c1_oar1. cr ." i2c1_oar1.  RW   $" I2C1_OAR1 @ dup hex.  bin1. ;
: i2c1_oar2. cr ." i2c1_oar2.  RW   $" I2C1_OAR2 @ dup hex.  bin1. ;
: i2c1_dr. cr ." i2c1_dr.  RW   $" I2C1_DR @ dup hex.  bin1. ;
: i2c1_sr1. cr ." i2c1_sr1.   $" I2C1_SR1 @ dup hex.  bin1. ;
: i2c1_sr2. cr ." i2c1_sr2.  RO   $" I2C1_SR2 @ dup hex.  bin1. ;
: i2c1_ccr. cr ." i2c1_ccr.  RW   $" I2C1_CCR @ dup hex.  bin1. ;
: i2c1_trise. cr ." i2c1_trise.  RW   $" I2C1_TRISE @ dup hex.  bin1. ;
: i2c1.
i2c1_cr1. 
i2c1_cr2. 
i2c1_oar1. 
i2c1_oar2. 
i2c1_dr. 
i2c1_sr1. 
i2c1_sr2. 
i2c1_ccr. 
i2c1_trise. 
;

: spi1_cr1. cr ." spi1_cr1.  RW   $" SPI1_CR1 @ dup hex.  bin1. ;
: spi1_cr2. cr ." spi1_cr2.  RW   $" SPI1_CR2 @ dup hex.  bin1. ;
: spi1_sr. cr ." spi1_sr.   $" SPI1_SR @ dup hex.  bin1. ;
: spi1_dr. cr ." spi1_dr.  RW   $" SPI1_DR @ dup hex.  bin1. ;
: spi1_crcpr. cr ." spi1_crcpr.  RW   $" SPI1_CRCPR @ dup hex.  bin1. ;
: spi1_rxcrcr. cr ." spi1_rxcrcr.  RO   $" SPI1_RXCRCR @ dup hex.  bin1. ;
: spi1_txcrcr. cr ." spi1_txcrcr.  RO   $" SPI1_TXCRCR @ dup hex.  bin1. ;
: spi1_i2scfgr. cr ." spi1_i2scfgr.  RW   $" SPI1_I2SCFGR @ dup hex.  bin1. ;
: spi1_i2spr. cr ." spi1_i2spr.  RW   $" SPI1_I2SPR @ dup hex.  bin1. ;
: spi1.
spi1_cr1. 
spi1_cr2. 
spi1_sr. 
spi1_dr. 
spi1_crcpr. 
spi1_rxcrcr. 
spi1_txcrcr. 
spi1_i2scfgr. 
spi1_i2spr. 
;

: adc1_sr. cr ." adc1_sr.  RW   $" ADC1_SR @ dup hex.  bin1. ;
: adc1_cr1. cr ." adc1_cr1.  RW   $" ADC1_CR1 @ dup hex.  bin1. ;
: adc1_cr2. cr ." adc1_cr2.  RW   $" ADC1_CR2 @ dup hex.  bin1. ;
: adc1_smpr1. cr ." adc1_smpr1.  RW   $" ADC1_SMPR1 @ dup hex.  bin1. ;
: adc1_smpr2. cr ." adc1_smpr2.  RW   $" ADC1_SMPR2 @ dup hex.  bin1. ;
: adc1_jofr1. cr ." adc1_jofr1.  RW   $" ADC1_JOFR1 @ dup hex.  bin1. ;
: adc1_jofr2. cr ." adc1_jofr2.  RW   $" ADC1_JOFR2 @ dup hex.  bin1. ;
: adc1_jofr3. cr ." adc1_jofr3.  RW   $" ADC1_JOFR3 @ dup hex.  bin1. ;
: adc1_jofr4. cr ." adc1_jofr4.  RW   $" ADC1_JOFR4 @ dup hex.  bin1. ;
: adc1_htr. cr ." adc1_htr.  RW   $" ADC1_HTR @ dup hex.  bin1. ;
: adc1_ltr. cr ." adc1_ltr.  RW   $" ADC1_LTR @ dup hex.  bin1. ;
: adc1_sqr1. cr ." adc1_sqr1.  RW   $" ADC1_SQR1 @ dup hex.  bin1. ;
: adc1_sqr2. cr ." adc1_sqr2.  RW   $" ADC1_SQR2 @ dup hex.  bin1. ;
: adc1_sqr3. cr ." adc1_sqr3.  RW   $" ADC1_SQR3 @ dup hex.  bin1. ;
: adc1_jsqr. cr ." adc1_jsqr.  RW   $" ADC1_JSQR @ dup hex.  bin1. ;
: adc1_jdr1. cr ." adc1_jdr1.  RO   $" ADC1_JDR1 @ dup hex.  bin1. ;
: adc1_jdr2. cr ." adc1_jdr2.  RO   $" ADC1_JDR2 @ dup hex.  bin1. ;
: adc1_jdr3. cr ." adc1_jdr3.  RO   $" ADC1_JDR3 @ dup hex.  bin1. ;
: adc1_jdr4. cr ." adc1_jdr4.  RO   $" ADC1_JDR4 @ dup hex.  bin1. ;
: adc1_dr. cr ." adc1_dr.  RO   $" ADC1_DR @ dup hex.  bin1. ;
: adc1.
adc1_sr. 
adc1_cr1. 
adc1_cr2. 
adc1_smpr1. 
adc1_smpr2. 
adc1_jofr1. 
adc1_jofr2. 
adc1_jofr3. 
adc1_jofr4. 
adc1_htr. 
adc1_ltr. 
adc1_sqr1. 
adc1_sqr2. 
adc1_sqr3. 
adc1_jsqr. 
adc1_jdr1. 
adc1_jdr2. 
adc1_jdr3. 
adc1_jdr4. 
adc1_dr. 
;

: dbg_idcode. cr ." dbg_idcode.  RO   $" DBG_IDCODE @ dup hex.  bin1. ;
: dbg_cr. cr ." dbg_cr.  RW   $" DBG_CR @ dup hex.  bin1. ;
: dbg.
dbg_idcode. 
dbg_cr. 
;

: nvic_ictr. cr ." nvic_ictr.  RO   $" NVIC_ICTR @ dup hex.  bin1. ;
: nvic_stir. cr ." NVIC_STIR " WRITEONLY ; 
: nvic_iser0. cr ." nvic_iser0.  RW   $" NVIC_ISER0 @ dup hex.  bin1. ;
: nvic_iser1. cr ." nvic_iser1.  RW   $" NVIC_ISER1 @ dup hex.  bin1. ;
: nvic_icer0. cr ." nvic_icer0.  RW   $" NVIC_ICER0 @ dup hex.  bin1. ;
: nvic_icer1. cr ." nvic_icer1.  RW   $" NVIC_ICER1 @ dup hex.  bin1. ;
: nvic_ispr0. cr ." nvic_ispr0.  RW   $" NVIC_ISPR0 @ dup hex.  bin1. ;
: nvic_ispr1. cr ." nvic_ispr1.  RW   $" NVIC_ISPR1 @ dup hex.  bin1. ;
: nvic_icpr0. cr ." nvic_icpr0.  RW   $" NVIC_ICPR0 @ dup hex.  bin1. ;
: nvic_icpr1. cr ." nvic_icpr1.  RW   $" NVIC_ICPR1 @ dup hex.  bin1. ;
: nvic_iabr0. cr ." nvic_iabr0.  RO   $" NVIC_IABR0 @ dup hex.  bin1. ;
: nvic_iabr1. cr ." nvic_iabr1.  RO   $" NVIC_IABR1 @ dup hex.  bin1. ;
: nvic_ipr0. cr ." nvic_ipr0.  RW   $" NVIC_IPR0 @ dup hex.  bin1. ;
: nvic_ipr1. cr ." nvic_ipr1.  RW   $" NVIC_IPR1 @ dup hex.  bin1. ;
: nvic_ipr2. cr ." nvic_ipr2.  RW   $" NVIC_IPR2 @ dup hex.  bin1. ;
: nvic_ipr3. cr ." nvic_ipr3.  RW   $" NVIC_IPR3 @ dup hex.  bin1. ;
: nvic_ipr4. cr ." nvic_ipr4.  RW   $" NVIC_IPR4 @ dup hex.  bin1. ;
: nvic_ipr5. cr ." nvic_ipr5.  RW   $" NVIC_IPR5 @ dup hex.  bin1. ;
: nvic_ipr6. cr ." nvic_ipr6.  RW   $" NVIC_IPR6 @ dup hex.  bin1. ;
: nvic_ipr7. cr ." nvic_ipr7.  RW   $" NVIC_IPR7 @ dup hex.  bin1. ;
: nvic_ipr8. cr ." nvic_ipr8.  RW   $" NVIC_IPR8 @ dup hex.  bin1. ;
: nvic_ipr9. cr ." nvic_ipr9.  RW   $" NVIC_IPR9 @ dup hex.  bin1. ;
: nvic_ipr10. cr ." nvic_ipr10.  RW   $" NVIC_IPR10 @ dup hex.  bin1. ;
: nvic_ipr11. cr ." nvic_ipr11.  RW   $" NVIC_IPR11 @ dup hex.  bin1. ;
: nvic_ipr12. cr ." nvic_ipr12.  RW   $" NVIC_IPR12 @ dup hex.  bin1. ;
: nvic_ipr13. cr ." nvic_ipr13.  RW   $" NVIC_IPR13 @ dup hex.  bin1. ;
: nvic_ipr14. cr ." nvic_ipr14.  RW   $" NVIC_IPR14 @ dup hex.  bin1. ;
: nvic.
nvic_ictr. 
nvic_stir. 
nvic_iser0. 
nvic_iser1. 
nvic_icer0. 
nvic_icer1. 
nvic_ispr0. 
nvic_ispr1. 
nvic_icpr0. 
nvic_icpr1. 
nvic_iabr0. 
nvic_iabr1. 
nvic_ipr0. 
nvic_ipr1. 
nvic_ipr2. 
nvic_ipr3. 
nvic_ipr4. 
nvic_ipr5. 
nvic_ipr6. 
nvic_ipr7. 
nvic_ipr8. 
nvic_ipr9. 
nvic_ipr10. 
nvic_ipr11. 
nvic_ipr12. 
nvic_ipr13. 
nvic_ipr14. 
;

compiletoram\ Program Name: f103-scb-constants.fs
\ Copyright 2022  t.porter , licensed under the GPL
\ For Mecrisp-Stellaris by Matthias Koch
\ Chip: STM32F103
\ All register names must be CMSIS-SVD compliant
\ Note: gpio a,b,c,d,e, and uart1 are enabled by Mecrisp-Stellaris core as default.
\
\ This Program : System control block (SCB) 
\ Note the SCB is not a part of the STM32F CMSIS-SVD
\ See: ST PM0056 Programming manual, page 149
\ 0xE000ED00-0xE000ED3F
\ ------------------------------------------------------------------------------------------------------  
compiletoflash 


\ SCB constants
$E000ED00 CONSTANT SCB_CPUID    \ RO $412FC231 CPUID Base Register    
$E000ED04 CONSTANT SCB_ICSR     \ $00000000 Interrupt Control and State Register
$E000ED08 CONSTANT SCB_VTOR     \ $00000000 Vector Table Offset Register  
$E000ED0C CONSTANT SCB_AIRCR    \ $00000000 Application Interrupt and Reset Control Register  
$E000ED10 CONSTANT SCB_SCR      \ $00000000 System Control Register 
$E000ED14 CONSTANT SCB_CCR      \ $00000200 Configuration and Control Register
$E000ED18 CONSTANT SCB_SHPR1    \ $00000000 System Handler Priority Register 1  
$E000ED1C CONSTANT SCB_SHPR2    \ $00000000 System Handler Priority Register 2 
$E000ED20 CONSTANT SCB_SHPR3    \ $00000000 System Handler Priority Register 3  
$E000ED24 CONSTANT SCB_SHCSR    \ $00000000 System Handler Control and State Register
$E000ED28 CONSTANT SCB_CFSR     \ $00000000 Configurable Fault Status Registers
$E000ED2C CONSTANT SCB_HFSR     \ $00000000 HardFault Status Register
\ $E000ED30 CONSTANT SCB_DFSR     \ $00000000 Debug Fault Status Register
$E000ED34 CONSTANT SCB_MMFAR     \ $00000000 MemManage Fault Address Register
$E000ED38 CONSTANT SCB_BFAR     \ BusFault Address Register
\ $E000ED3C CONSTANT SCB_AFSR     \ $00000000 Auxiliary Fault Status Register
\ $E000ED40 CONSTANT SCB_ID_PFR0  \ RO $00000030 Processor Feature Register 0
\ $E000ED44 CONSTANT SCB_ID_PFR1  \ RO $00000200 Processor Feature Register 1
\ $E000ED48 CONSTANT SCB_ID_DFR0  \ RO $00100000 Debug Features Register 0c
\ $E000ED4C CONSTANT SCB_ID_AFR0  \ RO $00000000 Auxiliary Features Register 0
\ $E000ED50 CONSTANT SCB_ID_MMFR0 \ RO $00100030 Memory Model Feature Register 0
\ $E000ED54 CONSTANT SCB_ID_MMFR1 \ RO $00000000 Memory Model Feature Register 1
\ $E000ED58 CONSTANT SCB_ID_MMFR2 \ RO $01000000 Memory Model Feature Register 2
\ $E000ED5C CONSTANT SCB_ID_MMFR3 \ RO $00000000 Memory Model Feature Register 3
\ $E000ED60 CONSTANT SCB_ID_ISAR0 \ RO $01100110 Instruction Set Attributes Register 0
\ $E000ED64 CONSTANT SCB_ID_ISAR1 \ RO $02111000 Instruction Set Attributes Register 1
\ $E000ED68 CONSTANT SCB_ID_ISAR2 \ RO $21112231 Instruction Set Attributes Register 2
\ $E000ED6C CONSTANT SCB_ID_ISAR3 \ RO $01111110 Instruction Set Attributes Register 3
\ $E000ED70 CONSTANT SCB_ID_ISAR4 \ RO $01310132 Instruction Set Attributes Register 4
\ $E000ED88 CONSTANT SCB_CPACR    \ RW $00000000 Coprocessor Access Control Register
\ $E000EF00 CONSTANT SCB_STIR     \ WO $00000000 Software Triggered Interrupt Register








compiletoram
compiletoflash

\ A convenient memory dump helper

\  : u.4 ( u -- ) 0 <# # # # # #> type ;
\  : u.2 ( u -- ) 0 <# # # #> type ;

: dump16 ( addr -- ) \ Print 16 bytes memory
  base @ >r hex
  $F bic
  dup hex. ." :  "

  dup 16 + over do
    i c@ u.2 space \ Print data with 2 digits
    i $F and 7 = if 2 spaces then
  loop

  ."  | "

  dup 16 + swap do
        i c@ 32 u>= i c@ 127 u< and if i c@ emit else [char] . emit then
        i $F and 7 = if 2 spaces then
      loop

  ."  |" cr
  r> base !
;

: dump ( addr len -- ) \ Print a memory region
  cr
  over 15 and if 16 + then \ One more line if not aligned on 16
  begin
    swap ( len addr )
    dup dump16
    16 + ( len addr+16 )
    swap 16 - ( addr+16 len-16 )
    dup 0<
  until
  2drop
;
\ ------------------------
\ Words4 a 4 columnar list
\ of words by tp
\ ------------------------

\ 148 bytes

compiletoflash

: words4 ( -- ) cr  \ A columnar Word list printer. Width = 20 characters, handles overlength Words neatly
   0                                \ column counter
   dictionarystart
      begin
         dup 6 + dup
         ctype                      \ dup before 6 is for dictionarynext input
         count nip                  \ get number of characters in the word and drop the address of the word
             20 swap - dup 0 > if   \ if Word is less than 20 chars
                   spaces swap      \ pad with spaces to equal 20 chars
                   else drop cr     \ issue immediate carriage return and drop negative number
                   nip -1           \ and reset to column -1
                   then
                      dup 3 = if 3 - cr \ if at 4th column, zero column counter
                      else 1 +
                      then
         swap
         dictionarynext             \   ( a-addr - - a-addr flag )
      until
   2drop
;

compiletoram
\ USB driver for STM32F103 by Jean-Claude Wippler,
\ based on the Coreforth USB driver by Eckhart Köppen
\ file:///usr/home/tp/projects/stm32f0-doc/sphinx/_build/html/usb-stm32f103.html
\ modified by tp to work with my system
\ configured for Shenzhen LC Technology board with STM32F103C8T6 which is the same as the Bluepill with USB-DP on PA12

\ The board specific code is in +usb and needs to be changed for other
\ ways to signal a new connection by pulling D+ low briefly.

\ Other configs are available here:
\ /home/tp/projects/programming-languages/forth/mecrisp-stellaris/library/embello-1608-forth/suf
\ ### Boards
\ * **generic** 
\ * **hotcbo** 
\ * **hytiny** 
\ * **maplemini** 
\ * **olimexino** 
\ * **olip103** 
\ * **port103z** 

compiletoflash

\ -----------------------------------------------------------------------------
\  Chip serial number
\ -----------------------------------------------------------------------------

: chipid ( -- u1 u2 u3 3 )  \ unique chip ID as N values on the stack
  $1FFFF7E8 @ $1FFFF7EC @ $1FFFF7F0 @ 3 ;
: hwid ( -- u )  \ a "fairly unique" hardware ID as single 32-bit int
  chipid 1 do xor loop ;

\ -----------------------------------------------------------------------------
\   Flash tools
\ -----------------------------------------------------------------------------

\ emulate c, which is not available in hardware on some chips.
\ copied from Mecrisp's common/charcomma.txt
0 variable c,collection

: c, ( c -- )  \ emulate c, with h,
  c,collection @ ?dup if $FF and swap 8 lshift or h,
                         0 c,collection !
                      else $100 or c,collection ! then ;

: calign ( -- )  \ must be called to flush after odd number of c, calls
  c,collection @ if 0 c, then ;


: flash-kb ( -- u )  \ return size of flash memory in KB
  $1FFFF7E0 h@ ;
: flash-pagesize ( addr - u )  \ return size of flash page at given address
  drop flash-kb 128 <= if 1024 else 2048 then ;

\ -----------------------------------------------------------------------------
\  Ring buffers
\ -----------------------------------------------------------------------------

\ ring buffers, for serial ports, etc - size must be 4..256 and power of 2
\ TODO setup is a bit messy right now, should put buffer: word inside init

\ each ring needs 4 extra bytes for internal housekeeping:
\   addr+0 = ring mask, i.e. N-1
\   addr+1 = put index: 0..255 (needs to be masked before use)
\   addr+2 = get index: 0..255 (needs to be masked before use)
\   addr+3 = spare
\   addr+4..addr+4+N-1 = actual ring buffer, N bytes
\ example:
\   16 4 + buffer: buf  buf 16 init-ring

: init-ring ( addr size -- )  \ initialise a ring buffer
  1- swap !  \ assumes little-endian so mask ends up in ring+0
;

: c++@ ( addr -- b addr+1 ) dup c@ swap 1+ ;  \ fetch and autoinc byte ptr

: ring-step ( ring 1/2 -- addr )  \ common code for saving and fetching
  over + ( ring ring-g/p ) dup c@ >r ( ring ring-g/p R: g/p )
  dup c@ 1+ swap c!  \ increment byte under ptr
  dup c@ r> and swap 4 + + ;

: ring# ( ring -- u )  \ return current number of bytes in the ring buffer
\ TODO could be turned into a single @ word access and made interrupt-safe
  c++@ c++@ c++@ drop - and ;
: ring? ( ring -- f )  \ true if the ring can accept more data
  dup ring# swap c@ < ;
: >ring ( b ring -- )  \ save byte to end of ring buffer
  1 ring-step c! ;
: ring> ( ring -- b )  \ fetch byte from start of ring buffer
  2 ring-step c@ ;

\ -----------------------------------------------------------------------------
\  USB Descriptors
\ -----------------------------------------------------------------------------

create usb:dev
  18 c,  \ bLength
  $01 c, \ USB_DEVICE_DESCRIPTOR_TYPE
  $00 c,
  $02 c, \ bcdUSB = 2.00
  $02 c, \ bDeviceClass: CDC
  $00 c, \ bDeviceSubClass
  $00 c, \ bDeviceProtocol
  $40 c, \ bMaxPacketSize0
  $83 c,
  $04 c, \ idVendor = 0x0483
  $40 c,
  $57 c, \ idProduct = 0x7540
  $00 c,
  $02 c, \ bcdDevice = 2.00
  1 c,     \ Index of string descriptor describing manufacturer
  2 c,     \ Index of string descriptor describing product
  3 c,     \ Index of string descriptor describing the device's serial number
  $01 c, \ bNumConfigurations
calign

create usb:conf  \ total length = 67 bytes
\ USB Configuration Descriptor
  9 c,   \ bLength: Configuration Descriptor size
  $02 c, \ USB_CONFIGURATION_DESCRIPTOR_TYPE
  67 c,  \ VIRTUAL_COM_PORT_SIZ_CONFIG_DESC
  0 c,
  2 c,   \ bNumInterfaces: 2 interface
  1 c,   \ bConfigurationValue
  0 c,   \ iConfiguration
  $C0 c, \ bmAttributes: self powered
  $32 c, \ MaxPower 0 mA
\ Interface Descriptor
  9 c,   \ bLength: Interface Descriptor size
  $04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
  $00 c, \ bInterfaceNumber: Number of Interface
  $00 c, \ bAlternateSetting: Alternate setting
  $01 c, \ bNumEndpoints: One endpoints used
  $02 c, \ bInterfaceClass: Communication Interface Class
  $02 c, \ bInterfaceSubClass: Abstract Control Model
  $01 c, \ bInterfaceProtocol: Common AT commands
  $00 c, \ iInterface:
\ Header Functional Descriptor
  5 c,   \ bLength: Endpoint Descriptor size
  $24 c, \ bDescriptorType: CS_INTERFACE
  $00 c, \ bDescriptorSubtype: Header Func Desc
  $10 c, \ bcdCDC: spec release number
  $01 c,
\ Call Management Functional Descriptor
  5 c,   \ bFunctionLength
  $24 c, \ bDescriptorType: CS_INTERFACE
  $01 c, \ bDescriptorSubtype: Call Management Func Desc
  $00 c, \ bmCapabilities: D0+D1
  $01 c, \ bDataInterface: 1
\ ACM Functional Descriptor
  4 c,   \ bFunctionLength
  $24 c, \ bDescriptorType: CS_INTERFACE
  $02 c, \ bDescriptorSubtype: Abstract Control Management desc
  $02 c, \ bmCapabilities
\ Union Functional Descriptor
  5 c,   \ bFunctionLength
  $24 c, \ bDescriptorType: CS_INTERFACE
  $06 c, \ bDescriptorSubtype: Union func desc
  $00 c, \ bMasterInterface: Communication class interface
  $01 c, \ bSlaveInterface0: Data Class Interface
\ Endpoint 2 Descriptor
  7 c,   \ bLength: Endpoint Descriptor size
  $05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
  $82 c, \ bEndpointAddress: (IN2)
  $03 c, \ bmAttributes: Interrupt
  8 c,   \ VIRTUAL_COM_PORT_INT_SIZE
  0 c,
  $FF c, \ bInterval:
\ Data class interface descriptor
  9 c,   \ bLength: Endpoint Descriptor size
  $04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
  $01 c, \ bInterfaceNumber: Number of Interface
  $00 c, \ bAlternateSetting: Alternate setting
  $02 c, \ bNumEndpoints: Two endpoints used
  $0A c, \ bInterfaceClass: CDC
  $00 c, \ bInterfaceSubClass:
  $00 c, \ bInterfaceProtocol:
  $00 c, \ iInterface:
\ Endpoint 3 Descriptor
  7 c,   \ bLength: Endpoint Descriptor size
  $05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
  $03 c, \ bEndpointAddress: (OUT3)
  $02 c, \ bmAttributes: Bulk
  64 c,  \ VIRTUAL_COM_PORT_DATA_SIZE
  0 c,
  $00 c, \ bInterval: ignore for Bulk transfer
\ Endpoint 1 Descriptor
  7 c,   \ bLength: Endpoint Descriptor size
  $05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
  $81 c, \ bEndpointAddress: (IN1)
  $02 c, \ bmAttributes: Bulk
  64 c,  \ VIRTUAL_COM_PORT_DATA_SIZE
  0 c,
  $00 c, \ bInterval
calign

create usb:langid
  4 c, 3 c,  \ USB_STRING_DESCRIPTOR_TYPE,
  $0409 h, \ LangID = U.S. English

create usb:vendor
  40 c, 3 c,  \ USB_STRING_DESCRIPTOR_TYPE,
  char M h, char e h, char c h, char r h, char i h, char s h, char p h,
  bl     h, char ( h, char S h, char T h, char M h, char 3 h, char 2 h,
  char F h, char 1 h, char 0 h, char x h, char ) h,

create usb:product
  36 c, 3 c,  \ USB_STRING_DESCRIPTOR_TYPE,
  char F h, char o h, char r h, char t h, char h h, bl     h, char S h,
  char e h, char r h, char i h, char a h, char l h, bl     h, char P h,
  char o h, char r h, char t h,

create usb:line
  hex 00 c, C2 c, 01 c, 00 c, 01 c, 00 c, 08 c, 00 c, decimal

\ -----------------------------------------------------------------------------
\  USB module initialisation values
\ -----------------------------------------------------------------------------

create usb:init
hex
  0080 h,  \ ADDR0_TX   control - rx: 64b @ +040/080, tx: 64b @ +080/100
  0000 h,  \ COUNT0_TX
  0040 h,  \ ADDR0_RX
  8400 h,  \ COUNT0_RX
  00C0 h,  \ ADDR1_TX   bulk - tx: 64b @ +0C0/180
  0000 h,  \ COUNT1_TX
  0000 h,  \ ADDR1_RX
  0000 h,  \ COUNT1_RX
  0140 h,  \ ADDR2_TX   interrupt - tx: 8b @ +140/280
  0000 h,  \ COUNT2_TX
  0000 h,  \ ADDR2_RX
  0000 h,  \ COUNT2_RX
  0000 h,  \ ADDR3_TX   bulk - rx: 64b @ +100/200
  0000 h,  \ COUNT3_TX
  0100 h,  \ ADDR3_RX
  8400 h,  \ COUNT3_RX
decimal

$40006000 constant USBMEM

\ -----------------------------------------------------------------------------
\  USB peripheral module handling
\ -----------------------------------------------------------------------------

: usb-pma ( pos -- addr ) dup 1 and negate swap 2* + USBMEM + ;
: usb-pma@ ( pos -- u ) usb-pma h@ ;
: usb-pma! ( u pos -- ) usb-pma h! ;

: ep-addr ( ep -- addr ) cells USB_EP0R + ;
: ep-reg ( ep n -- addr ) 2* swap 8 * + usb-pma ;

: rxstat! ( ep u -- )  \ set stat_rx without toggling/setting any other fields
  swap ep-addr >r
  12 lshift  r@ h@ tuck  xor
\  R^rrseekT^ttnnnn
\  5432109876543210
  %0011000000000000 and swap
  %0000111100001111 and
  %1000000010000000 or
  or r> h! ;

: txstat! ( ep u -- )  \ set stat_tx without toggling/setting any other fields
  swap ep-addr >r
  4 lshift  r@ h@ tuck  xor
\  R^rrseekT^ttnnnn
\  5432109876543210
  %0000000000110000 and swap
  %0000111100001111 and
  %1000000010000000 or
  or r> h! ;

: ep-reset-rx# ( ep -- ) $8400 over 3 ep-reg h! 3 rxstat! ;
: rxclear ( ep -- ) ep-addr dup h@ $7FFF and $8F8F and swap h! ;
: txclear ( ep -- ) ep-addr dup h@ $FF7F and $8F8F and swap h! ;

0 0 2variable usb-pend
18 buffer: usb-serial

: set-serial ( -- addr )  \ fill serial number in as UTF-16 descriptor
  base @ hex
  hwid 0 <# 8 0 do # loop #> ( base addr 8 )
  0 do dup c@ i 1+ 2* usb-serial + h! 1+ loop
  drop base !
  usb-serial $0312 over h! ;

: send-data ( addr n -- ) usb-pend 2! ;
: send-next ( -- )
  usb-pend 2@ 64 min $46 usb-pma@ min
  >r ( addr R: num )
  r@ even 0 ?do
    dup i + h@ $80 i + usb-pma!
  2 +loop drop
  r@ $02 usb-pma! 0 3 txstat!
  usb-pend 2@ r> dup negate d+ usb-pend 2! ;

: send-desc ( -- )
  $42 usb-pma@ case
    $0100 of usb:dev     18 endof
    $0200 of usb:conf    67 endof
    $0300 of usb:langid  4  endof
    $0301 of usb:vendor  40 endof
    $0302 of usb:product 36 endof
    $0303 of set-serial  18 endof
    true ?of 0           0  endof
  endcase send-data ;

: usb-reset ( -- )
  256 0 do  0 i 2* usb-pma! loop  0 USB_BTABLE h!
  usb:init  64 0 do
    dup h@  i USBMEM + h!
    2+
  4 +loop  drop
  $3210 0 ep-addr h!
  $0021 1 ep-addr h!
  $0622 2 ep-addr h!
  $3003 3 ep-addr h!
  $80 USB_DADDR h! ;

\ -----------------------------------------------------------------------------
\  USB packet handling
\ -----------------------------------------------------------------------------

create zero 0 ,

128 4 + buffer: usb-in-ring   \ RX ring buffer, ample for mecrisp input lines
 64 4 + buffer: usb-out-ring  \ TX ring buffer, for outbound bytes

: ep-setup ( ep -- )  \ setup packets, sent from host to config this device
  dup rxclear
  $41 usb-pma c@ case
    $00 of zero 2 send-data endof
    $06 of send-desc endof
    ( default ) 0 0 send-data
  endcase
  ep-reset-rx# send-next ;

0 variable tx.pend
0 variable usb.ticks

: usb-pma-c! ( b pos -- )  \ careful, can't write high bytes separately
  dup 1 and if
    1- dup usb-pma@ rot 8 lshift or swap
  then usb-pma! ;

: usb-fill ( -- )  \ fill the USB outbound buffer from the TX ring buffer
  usb-out-ring ring# ?dup if
    dup tx.pend !
    dup 0 do usb-out-ring ring> $C0 i + usb-pma-c!  loop
    1 1 ep-reg h! 1 3 txstat!
  then ;

: ep-out ( ep -- )  \ outgoing packets, sent from host to this device
\ dup 2 rxstat!  \ set RX state to NAK
  dup if  \ only pick up data for endpoint 3
    usb-in-ring ring# 60 > if drop exit then  \ reject if no room in ring
    dup 3 ep-reg h@ $7F and 0 ?do
      i $100 + usb-pma c@ usb-in-ring >ring
    loop
  then
  dup rxclear
  ep-reset-rx# ;

: ep-in ( ep -- )  \ incoming polls, sent from this device to host
  dup if
    0 usb.ticks !  0 tx.pend !  usb-fill
  else
    $41 usb-pma c@ $05 = if $42 usb-pma@ $80 or USB_DADDR h! then
    send-next
  then
  txclear ;

: usb-ctr ( istr -- )
  dup $07 and swap $10 and if 
    dup ep-addr h@ $800 and if ep-setup else ep-out then
  else ep-in then ;

: usb-flush
  usb-in-ring 128 init-ring
  usb-out-ring 64 init-ring ;

: usb-poll
  \ clear ring buffers if pending output is not getting sent to host
  tx.pend @ if
    1 usb.ticks +!
    usb.ticks @ 10000 u> if usb-flush then
  then
  \ main USB driver polling
  USB_ISTR h@
  dup $8000 and if dup usb-ctr                            then
  dup $0400 and if usb-reset            $FBFF USB_ISTR h! then
  dup $0800 and if %1100 USB_CNTR hbis! $F7FF USB_ISTR h! then
      $1000 and if %1000 USB_CNTR hbic! $EFFF USB_ISTR h! then ;

: usb-key? ( -- f )  pause usb-poll usb-in-ring ring# 0<> ;
: usb-key ( -- c )  begin usb-key? until  usb-in-ring ring> ;
: usb-emit? ( -- f )  usb-poll usb-out-ring ring? ;
: usb-emit ( c -- )  begin usb-emit? until  usb-out-ring >ring
                     tx.pend @ 0= if usb-fill then ;

: usb-io ( -- )  \ start up USB and switch console I/O to it
  23 bit $4002101C bis!  \ USB ENABLE
  $0001 USB_CNTR h! ( 10 us ) $0000 USB_CNTR h!  \ FRES
  usb-flush
  ['] usb-key? hook-key? !
  ['] usb-key hook-key !
  1000000 0 do usb-poll loop
  ['] usb-emit? hook-emit? !
  ['] usb-emit hook-emit !
  \ ['] usb-poll hook-pause !
;

\ -----------------------------------------------------------------------------
\  USB connect and disconnect, board specific !
\ -----------------------------------------------------------------------------

: init.usb ( -- )  \ Init USB hardware and switch to USB terminal
   72mhz \ This is required for USB use 
   \ moved to seperate " usbdp " Word by tp
   \ original jeelabs code
   \ Board-specific way to briefly pull USB-DP down via PA12 for 1ms
   \   $00050000 $40010804 ( PORTA_CRH ) bis!   \ PA12 Open-Drain Output, ( dont affect serial ports ).
   \   12 bit $4001080C ( PORTA_ODR ) bic!	\ PA12 LOW
   \   1000 0 do loop				\ approx 1ms delay
   \   12 bit $4001080C ( PORTA_ODR ) bis!	\ PA12 HIGH
  usb-io
;

: deinit.usb ( -- )	   \ Deinit USB hardware, switch back to swdcom terminal
  23 bit $4002101C bic!	   \ Usb peripheral disable RCC_APB1ENR_USBEN
  \ 1 12 lshift $4001080C ( PORTA_ODR )  bic!  \ original jeelabs code:  PC12 = 0
  ['] swd-key? hook-key? !
  ['] swd-key hook-key !
  ['] swd-emit? hook-emit? !
  ['] swd-emit hook-emit !
  \ ['] nop hook-pause !
;

: +usb ( -- ) init.usb ;
: -usb ( -- ) deinit.usb ;

\ -----------------------------------------------------------------------------

\ : init ( -- ) +usb ;	   \ or -usb


\ Program Name: memstat.fs
\ Date: Sun 12 Jan 2022 18:55:01 AEDT
\ Copyright 2022 by t.j.porter , licensed under the GPLV2
\ For Mecrisp-Stellaris and Mecrisp-Quintus by Matthias Koch.
\ https://sourceforge.net/projects/mecrisp/
\ Standalone: no preloaded support files required
\
\ This Program : Displays memory statistics
\
\ ---------------------------------------------------------------------------\
\     Usage:    " ramsize-kb flashmod flash-size-register-address memstats "
\
\     'ramsize-kb' = Get the MCU ram size from the datasheet as it's not 
\     available from the mcu directly like the flash size.
\
\     'flashmod' = flash size modifier
\	 '1' = normal use, flash exactly as reported
\
\	 '2' = doubles the reported flash size. Only for a STM32F103C8 which
\	 reports 64kB of Flash but actually has DOUBLE (128kB) that size.
\	 OR if you suspect your chip MAY have double the flash advertized. Note:
\	 will crash this program with a Exception if it doesn't!
\
\     'flash-size-register-address' = "Flash size data register address". Check
\     your STM reference manual "Device electronic signature" section for the
\     correct address.
\
\ --------------------------- MCU Type Examples -----------------------------\
\  
\ ram-size  flashmod	ram-size    MCU Type
\ -kb			-register   
\			-address
\ --------  ---------   ---------   --------
\  8	    1		$1FFFF7CC   STM32F0xx
\  20	    1		$1FFFF7E0   STM32F10xx
\  20	    2		$1FFFF7E0   STM32F103C8 (2x indicated Flash)
\  20	    1		$1FFFF7E0   CKS32F103C8T6 (Chinese STM32F103CB clone)
\  32	    1		$1FFFF7E0   GD32VF103 RISC-V32, Mecrisp-Quintus
\  20	    1		$1FF8007C   STM32L0x3
\  64	    1		$1FFF7A22   STM32F407,415,427,437,429,439
\ 
\ ----------------------------- Screenshot ----------------------------------\

\ ---------------------------------------------------------------------------\
 \ compiletoram
 compiletoflash

 : flashfree ( -- u )
   compiletoram?
   compiletoflash		     
   unused
   swap			    
      if compiletoram
      then			    
 ;
 
 : ramfree ( u -- u ) 
   compiletoram? not      		    
   compiletoram	   
   unused
   swap			   	   		   
      if compiletoflash	   
      then
 ;

 : flashfree. ( u addr -- )	    \ 2 $1FFFF7E0 flashfree.
   @ $FFFF and 1024 * * dup dup
   ."  Flash Total:" .
   ."  Used:" flashfree - dup .
   ."  Free:" - .
   cr ;

 : ramfree. ( u -- )		    \ 20 ramfree.
   1024 * dup dup
   ."  Ram Total:" .
   ."  Used:" ramfree - dup . 
   ."  Free:" - .
   cr ;
 
 : memstats ( u u addr -- ) cr	    \ 20 2 $1FFFF7E0 memstats
   ." Memory stats in bytes: " cr   
   flashfree.
   ramfree.
 ; 
     
 compiletoram
 
 \ Possible usage examples
 \ : free ( -- ) 32 1 $1FFFF7E0 memstats ;  \ GD32VF103 
 \ : free ( -- ) 20 2 $1FFFF7E0 memstats ;  \ STM32F103C8
 \ : free ( -- )  8 1 $1FFFF7CC memstats ;  \ STM32F0xx 

 \ free


\ Partial ARM Cortex M3/M4 Disassembler, Copyright (C) 2013  Matthias Koch
\ This is free software under GNU General Public License v3.
\ Knows all M0 and some M3/M4 machine instructions, 
\ resolves call entry points, literal pools and handles inline strings.
\ Usage: Specify your target address in disasm-$ and give disasm-step some calls.

compiletoflash

 0 variable   word.start      \ added tp 
 0 variable   word.end	      \ added tp 

\ ---------------------------------------
\  Memory pointer and instruction fetch
\ ---------------------------------------

0 variable disasm-$   \ Current position for disassembling

: disasm-fetch        \ ( -- Data ) Fetches opcodes and operands, increments disasm-$
    disasm-$ @ h@     \             Holt Opcode oder Operand, incrementiert disasm-$
  2 disasm-$ +!   ;

\ --------------------------------------------------
\  Try to find address as code start in Dictionary 
\ --------------------------------------------------

: disasm-string ( -- ) \ Takes care of an inline string
  disasm-$ @ dup ctype skipstring disasm-$ !
;

: name. ( Address -- ) \ If the address is Code-Start of a dictionary word, it gets named.
  1 bic \ Thumb has LSB of address set.

  >r
  dictionarystart
  begin
    dup   6 + dup skipstring r@ = if ."   --> " ctype else drop then
    dictionarynext
  until
  drop
  r> 

  case \ Check for inline strings ! They are introduced by calls to ." or s" internals.
    ['] ." $1E + of ."   -->  .' " disasm-string ." '" endof \ It is ." runtime ?
    ['] s"  $4 + of ."   -->  s' " disasm-string ." '" endof \ It is .s runtime ?
    ['] c"  $4 + of ."   -->  c' " disasm-string ." '" endof \ It is .c runtime ?
  endcase
;

\ -------------------
\  Beautiful output
\ -------------------

: register. ( u -- )
  case 
    13 of ."  sp" endof
    14 of ."  lr" endof
    15 of ."  pc" endof
    dup ."  r" decimal u.ns hex 
  endcase ;


\ ----------------------------------------
\  Disassembler logic and opcode cutters
\ ----------------------------------------

: opcode? ( Opcode Bits Mask -- Opcode ? ) \ (Opcode and Mask) = Bits
  rot ( Bits Mask Opcode )
  tuck ( Bits Opcode Mask Opcode )
  and ( Bits Opcode Opcode* )
  rot ( Opcode Opcode* Bits )
  =
;

: reg.    ( Opcode Position -- Opcode ) over swap rshift  $7 and register. ;
: reg16.  ( Opcode Position -- Opcode ) over swap rshift  $F and register. ;
: reg16split. ( Opcode -- Opcode ) dup $0007 and over 4 rshift $0008 and or register. ;
: registerlist. ( Opcode -- Opcode ) 8 0 do dup 1 i lshift and if i register. space then loop ;

: imm3. ( Opcode Position -- Opcode ) over swap rshift  $7  and const. ;
: imm5. ( Opcode Position -- Opcode ) over swap rshift  $1F and const. ;
: imm8. ( Opcode Position -- Opcode ) over swap rshift  $FF and const. ;

: imm3<<1. ( Opcode Position -- Opcode ) over swap rshift  $7  and shl const. ;
: imm5<<1. ( Opcode Position -- Opcode ) over swap rshift  $1F and shl const. ;
: imm8<<1. ( Opcode Position -- Opcode ) over swap rshift  $FF and shl const. ;

: imm3<<2. ( Opcode Position -- Opcode ) over swap rshift  $7  and shl shl const. ;
: imm5<<2. ( Opcode Position -- Opcode ) over swap rshift  $1F and shl shl const. ;
: imm7<<2. ( Opcode Position -- Opcode ) over swap rshift  $7F and shl shl const. ;
: imm8<<2. ( Opcode Position -- Opcode ) over swap rshift  $FF and shl shl const. ;

: condition. ( Condition -- )
  case
    $0 of ." eq" endof  \ Z set
    $1 of ." ne" endof  \ Z clear
    $2 of ." cs" endof  \ C set
    $3 of ." cc" endof  \ C clear
                       
    $4 of ." mi" endof  \ N set
    $5 of ." pl" endof  \ N clear
    $6 of ." vs" endof  \ V set
    $7 of ." vc" endof  \ V clear
                       
    $8 of ." hi" endof  \ C set Z clear
    $9 of ." ls" endof  \ C clear or Z set
    $A of ." ge" endof  \ N == V
    $B of ." lt" endof  \ N != V
                       
    $C of ." gt" endof  \ Z==0 and N == V
    $D of ." le" endof  \ Z==1 or N != V
  endcase
;

: rotateleft  ( x u -- x ) 0 ?do rol loop ;
: rotateright ( x u -- x ) 0 ?do ror loop ;

: imm12. ( Opcode -- Opcode )
  dup $FF and                 \ Bits 0-7
  over  4 rshift $700 and or  \ Bits 8-10
  over 15 rshift $800 and or  \ Bit  11
  ( Opcode imm12 )
  dup 8 rshift
  case
    0 of $FF and                                  const. endof \ Plain 8 Bit Constant
    1 of $FF and                 dup 16 lshift or const. endof \ 0x00XY00XY
    2 of $FF and        8 lshift dup 16 lshift or const. endof \ 0xXY00XY00
    3 of $FF and dup 8 lshift or dup 16 lshift or const. endof \ 0xXYXYXYXY

    \ Shifted 8-Bit Constant
    swap
      \ Otherwise, the 32-bit constant is rotated left until the most significant bit is bit[7]. The size of the left
      \ rotation is encoded in bits[11:7], overwriting bit[7]. imm12 is bits[11:0] of the result.
      dup 7 rshift swap $7F and $80 or swap rotateright const.
  endcase
;

\ --------------------------------------
\  Name resolving for blx r0 sequences
\ --------------------------------------

0 variable destination-r0

\ ----------------------------------
\  Single instruction disassembler
\ ----------------------------------

: disasm-thumb-2 ( Opcode16 -- Opcode16 )
  dup 16 lshift disasm-fetch or ( Opcode16 Opcode32 )

  $F000D000 $F800D000 opcode? if  \ BL
                                ( Opcode )
                                ." _bl  "
                                dup $7FF and ( Opcode DestinationL )
                                over ( Opcode DestinationL Opcode )
                                16 rshift $7FF and ( Opcode DestinationL DestinationH )
                                dup $400 and if $FFFFF800 or then ( Opcode DestinationL DestinationHsigned )
                                11 lshift or ( Opcode Destination )
                                shl 
                                disasm-$ @ +
                                dup addr. name. \ Try to resolve destination
                              then

  \ MOVW / MOVT
  \ 1111 0x10 t100 xxxx 0xxx dddd xxxx xxxx
  \ F    2    4    0    0    0    0    0
  \ F    B    7    0    8    0    0    0

  $F2400000 $FB708000 opcode? if \ MOVW / MOVT
                                ( Opcode )
                                dup $00800000 and if ." movt"
                                                  else ." movw"
                                                  then

                                8 reg16. \ Destination register

                                \ Extract 16 Bit constant from opcode:
                                dup        $FF and              ( Opcode Constant* )
                                over     $7000 and  4 rshift or ( Opcode Constant** )
                                over $04000000 and 15 rshift or ( Opcode Constant*** )
                                over $000F0000 and  4 rshift or ( Opcode Constant )
                                dup ."  #" u.4
                                ( Opcode Constant )
                                over $00800000 and if 16 lshift destination-r0 @ or destination-r0 !
                                                   else                             destination-r0 !
                                                   then
                              then

  \ 
  \ 1111 0i0x xxxs nnnn 0iii dddd iiii iiii
  \ F    0    0    0    0    0    0    0
  \ F    A    0    0    8    0    0    0

  $F0000000 $FA008000 opcode? not if else \ Data processing, modified 12-bit immediate
                                dup 21 rshift $F and
                                case
                                  %0000 of ." and" endof
                                  %0001 of ." bic" endof
                                  %0010 of ." orr" endof
                                  %0011 of ." orn" endof
                                  %0100 of ." eor" endof
                                  %1000 of ." add" endof
                                  %1010 of ." adc" endof
                                  %1011 of ." sbc" endof
                                  %1101 of ." sub" endof
                                  %1110 of ." rsb" endof
                                  ." ?"
                                endcase
                                dup 1 20 lshift and if ." s" then \ Set Flags ?
                                8 reg16. 16 reg16. \ Destionation and Source registers
                                imm12.
                              then

  case \ Decode remaining "singular" opcodes used in Mecrisp-Stellaris:

    $EA5F0676 of ." rors r6 r6 #1" endof

    $F8470D04 of ." str r0 [ r7 #-4 ]!" endof
    $F8471D04 of ." str r1 [ r7 #-4 ]!" endof
    $F8472D04 of ." str r2 [ r7 #-4 ]!" endof
    $F8473D04 of ." str r3 [ r7 #-4 ]!" endof
    $F8476D04 of ." str r6 [ r7 #-4 ]!" endof

    $F8576026 of ." ldr r6 [ r7 r6 lsl #2 ]" endof
    $F85D6C08 of ." ldr r6 [ sp #-8 ]" endof

    $FAB6F686 of ." clz r6 r6" endof

    $FB90F6F6 of ." sdiv r6 r0 r6" endof
    $FBB0F6F6 of ." udiv r6 r0 r6" endof
    $FBA00606 of ." umull r0 r6 r0 r6" endof
    $FBA00806 of ." smull r0 r6 r0 r6" endof

  endcase \ Case drops Opcode32
  ( Opcode16 )
;

: disasm ( -- ) \ Disassembles one machine instruction and advances disasm-$

disasm-fetch \ Instruction opcode on stack the whole time.

$4140 $FFC0 opcode? if ." adcs"  0 reg. 3 reg. then          \ ADC
$1C00 $FE00 opcode? if ." adds" 0 reg. 3 reg. 6 imm3. then   \ ADD(1) small immediate two registers
$3000 $F800 opcode? if ." adds" 8 reg. 0 imm8. then          \ ADD(2) big immediate one register
$1800 $FE00 opcode? if ." adds" 0 reg. 3 reg. 6 reg. then    \ ADD(3) three registers
$4400 $FF00 opcode? if ." add"  reg16split. 3 reg16. then    \ ADD(4) two registers one or both high no flags
$A000 $F800 opcode? if ." add"  8 reg. ."  pc " 0 imm8<<2. then  \ ADD(5) rd = pc plus immediate
$A800 $F800 opcode? if ." add"  8 reg. ."  sp " 0 imm8<<2. then  \ ADD(6) rd = sp plus immediate
$B000 $FF80 opcode? if ." add sp" 0 imm7<<2. then            \ ADD(7) sp plus immediate

$4000 $FFC0 opcode? if ." ands" 0 reg. 3 reg. then           \ AND
$1000 $F800 opcode? if ." asrs" 0 reg. 3 reg. 6 imm5. then   \ ASR(1) two register immediate
$4100 $FFC0 opcode? if ." asrs" 0 reg. 3 reg. then           \ ASR(2) two register
$D000 $F000 opcode? not if else dup $0F00 and 8 rshift       \ B(1) conditional branch
                       case
                         $00 of ." beq" endof  \ Z set
                         $01 of ." bne" endof  \ Z clear
                         $02 of ." bcs" endof  \ C set
                         $03 of ." bcc" endof  \ C clear
                       
                         $04 of ." bmi" endof  \ N set
                         $05 of ." bpl" endof  \ N clear
                         $06 of ." bvs" endof  \ V set
                         $07 of ." bvc" endof  \ V clear
                       
                         $08 of ." bhi" endof  \ C set Z clear
                         $09 of ." bls" endof  \ C clear or Z set
                         $0A of ." bge" endof  \ N == V
                         $0B of ." blt" endof  \ N != V
                       
                         $0C of ." bgt" endof  \ Z==0 and N == V
                         $0D of ." ble" endof  \ Z==1 or N != V
                         \ $0E: Undefined Instruction
                         \ $0F: SWI                       
                       endcase
                       space
                       dup $FF and dup $80 and if $FFFFFF00 or then
                       shl disasm-$ @ 1 bic + 2 + addr. 
                    then

$E000 $F800 opcode? if ." b"                                 \ B(2) unconditional branch
                      dup $7FF and shl
                      dup $800 and if $FFFFF000 or then
                      disasm-$ @ + 2+                     
                      space addr.
                    then

$4380 $FFC0 opcode? if ." bics" 0 reg. 3 reg. then           \ BIC
$BE00 $FF00 opcode? if ." bkpt" 0 imm8. then                 \ BKPT

\ BL/BLX handled as Thumb-2 instruction on M3/M4.

$4780 $FF87 opcode? if ." blx"  3 reg16. then                \ BLX(2)
$4700 $FF87 opcode? if ." bx"   3 reg16. then                \ BX
$42C0 $FFC0 opcode? if ." cmns" 0 reg. 3 reg. then           \ CMN
$2800 $F800 opcode? if ." cmp"  8 reg. 0 imm8. then          \ CMP(1) compare immediate
$4280 $FFC0 opcode? if ." cmp"  0 reg. 3 reg. then           \ CMP(2) compare register
$4500 $FF00 opcode? if ." cmp"  reg16split. 3 reg16. then    \ CMP(3) compare high register
$B660 $FFE8 opcode? if ." cps"  0 imm5. then                 \ CPS
$4040 $FFC0 opcode? if ." eors" 0 reg. 3 reg. then           \ EOR

$C800 $F800 opcode? if ." ldmia" 8 reg. ."  {" registerlist. ." }" then     \ LDMIA

$6800 $F800 opcode? if ." ldr" 0 reg. ."  [" 3 reg. 6 imm5<<2. ."  ]" then  \ LDR(1) two register immediate
$5800 $FE00 opcode? if ." ldr" 0 reg. ."  [" 3 reg. 6 reg. ."  ]" then      \ LDR(2) three register
$4800 $F800 opcode? if ." ldr" 8 reg. ."  [ pc" 0 imm8<<2. ."  ]  Literal " \ LDR(3) literal pool
                       dup $FF and shl shl ( Opcode Offset ) \ Offset for PC
                       disasm-$ @ 2+ 3 bic + ( Opcode Address )
                       dup addr. ." : " @ addr. then

$9800 $F800 opcode? if ." ldr"  8 reg. ."  [ sp" 0 imm8<<2. ."  ]" then     \ LDR(4)

$7800 $F800 opcode? if ." ldrb" 0 reg. ."  [" 3 reg. 6 imm5. ."  ]" then    \ LDRB(1) two register immediate
$5C00 $FE00 opcode? if ." ldrb" 0 reg. ."  [" 3 reg. 6 reg.  ."  ]" then    \ LDRB(2) three register

$8800 $F800 opcode? if ." ldrh" 0 reg. ."  [" 3 reg. 6 imm5<<1. ."  ]" then \ LDRH(1) two register immediate
$5A00 $FE00 opcode? if ." ldrh" 0 reg. ."  [" 3 reg. 6 reg.  ."  ]" then    \ LDRH(2) three register

$5600 $FE00 opcode? if ." ldrsb" 0 reg. ."  [" 3 reg. 6 reg. ."  ]" then    \ LDRSB
$5E00 $FE00 opcode? if ." ldrsh" 0 reg. ."  [" 3 reg. 6 reg. ."  ]" then    \ LDRSH

$0000 $F800 opcode? if ." lsls" 0 reg. 3 reg. 6 imm5. then   \ LSL(1)
$4080 $FFC0 opcode? if ." lsls" 0 reg. 3 reg. then           \ LSL(2) two register
$0800 $F800 opcode? if ." lsrs" 0 reg. 3 reg. 6 imm5. then   \ LSR(1) two register immediate
$40C0 $FFC0 opcode? if ." lsrs" 0 reg. 3 reg. then           \ LSR(2) two register
$2000 $F800 opcode? if ." movs" 8 reg. 0 imm8. then          \ MOV(1) immediate
$4600 $FF00 opcode? if ." mov" reg16split. 3 reg16. then     \ MOV(3)

$4340 $FFC0 opcode? if ." muls" 0 reg. 3 reg. then           \ MUL
$43C0 $FFC0 opcode? if ." mvns" 0 reg. 3 reg. then           \ MVN
$4240 $FFC0 opcode? if ." negs" 0 reg. 3 reg. then           \ NEG
$4300 $FFC0 opcode? if ." orrs" 0 reg. 3 reg. then           \ ORR

$BC00 $FE00 opcode? if ." pop {"  registerlist. dup $0100 and if ."  pc " then ." }" then \ POP
$B400 $FE00 opcode? if ." push {" registerlist. dup $0100 and if ."  lr " then ." }" then \ PUSH

$BA00 $FFC0 opcode? if ." rev"   0 reg. 3 reg. then         \ REV
$BA40 $FFC0 opcode? if ." rev16" 0 reg. 3 reg. then         \ REV16
$BAC0 $FFC0 opcode? if ." revsh" 0 reg. 3 reg. then         \ REVSH
$41C0 $FFC0 opcode? if ." rors"  0 reg. 3 reg. then         \ ROR
$4180 $FFC0 opcode? if ." sbcs"  0 reg. 3 reg. then         \ SBC
$B650 $FFF7 opcode? if ." setend" then                      \ SETEND

$C000 $F800 opcode? if ." stmia" 8 reg. ."  {" registerlist. ." }" then     \ STMIA

$6000 $F800 opcode? if ." str" 0 reg. ."  [" 3 reg. 6 imm5<<2. ."  ]" then  \ STR(1) two register immediate
$5000 $FE00 opcode? if ." str" 0 reg. ."  [" 3 reg. 6 reg. ."  ]" then      \ STR(2) three register
$9000 $F800 opcode? if ." str" 8 reg. ."  [ sp + " 0 imm8<<2. ."  ]" then   \ STR(3)

$7000 $F800 opcode? if ." strb" 0 reg. ."  [" 3 reg. 6 imm5. ."  ]" then    \ STRB(1) two register immediate
$5400 $FE00 opcode? if ." strb" 0 reg. ."  [" 3 reg. 6 reg.  ."  ]" then    \ STRB(2) three register

$8000 $F800 opcode? if ." strh" 0 reg. ."  [" 3 reg. 6 imm5<<1. ."  ]" then \ STRH(1) two register immediate
$5200 $FE00 opcode? if ." strh" 0 reg. ."  [" 3 reg. 6 reg.  ."  ]" then    \ STRH(2) three register

$1E00 $FE00 opcode? if ." subs" 0 reg. 3 reg. 6 imm3. then   \ SUB(1)
$3800 $F800 opcode? if ." subs" 8 reg. 0 imm8. then          \ SUB(2)
$1A00 $FE00 opcode? if ." subs" 0 reg. 3 reg. 6 reg. then    \ SUB(3)
$B080 $FF80 opcode? if ." sub sp" 0 imm7<<2. then            \ SUB(4)

$DF00 $FF00 opcode? if ." swi"  0 imm8. then                 \ SWI
$B240 $FFC0 opcode? if ." sxtb" 0 reg. 3 reg. then           \ SXTB
$B200 $FFC0 opcode? if ." sxth" 0 reg. 3 reg. then           \ SXTH
$4200 $FFC0 opcode? if ." tst"  0 reg. 3 reg. then           \ TST
$B2C0 $FFC0 opcode? if ." uxtb" 0 reg. 3 reg. then           \ UXTB
$B280 $FFC0 opcode? if ." uxth" 0 reg. 3 reg. then           \ UXTH


\ 16 Bit Thumb-2 instruction ?

$BF00 $FF00 opcode? not if else                              \ IT...
                      dup $000F and
                      case
                        $8 of ." it" endof

                        over $10 and if else $8 xor then
                        $C of ." itt" endof
                        $4 of ." ite" endof

                        over $10 and if else $4 xor then
                        $E of ." ittt" endof
                        $6 of ." itet" endof
                        $A of ." itte" endof
                        $2 of ." itee" endof

                        over $10 and if else $2 xor then
                        $F of ." itttt" endof
                        $7 of ." itett" endof
                        $B of ." ittet" endof
                        $3 of ." iteet" endof
                        $D of ." ittte" endof
                        $5 of ." itete" endof
                        $9 of ." ittee" endof
                        $1 of ." iteee" endof
                      endcase
                      space
                      dup $00F0 and 4 rshift condition.
                    then

\ 32 Bit Thumb-2 instruction ?

$E800 $F800 opcode? if disasm-thumb-2 then
$F000 $F000 opcode? if disasm-thumb-2 then


\ If nothing of the above hits: Invalid Instruction... They are not checked for.

\ Try name resolving for blx r0 sequences:

$2000 $FF00 opcode? if dup $FF and destination-r0  ! then \ movs r0, #...
$3000 $FF00 opcode? if dup $FF and destination-r0 +! then \ adds r0, #...
$0000 $F83F opcode? if destination-r0 @                   \ lsls r0, r0, #...
                         over $07C0 and 6 rshift lshift
                       destination-r0 ! then
dup $4780 =         if destination-r0 @ name. then        \ blx r0

drop \ Forget opcode
; \ disasm

\ ------------------------------
\  Single instruction printing
\ ------------------------------

: memstamp \ ( Addr -- ) Shows a memory location nicely
    dup u.8 ." : " h@ u.4 ."   " ;

: disasm-step ( -- )
    disasm-$ @                 \ Note current position
    dup memstamp disasm cr     \ Disassemble one instruction

    begin \ Write out all disassembled memory locations
      2+ dup disasm-$ @ <>
    while
      dup memstamp cr
    repeat
    drop
;

\ ------------------------------
\  Disassembler for definitions
\ ------------------------------

: seec ( -- ) \ Continues to see
  base @ hex cr

  begin
    disasm-$ @ h@           $4770 =  \ Flag: Loop terminates with bx lr
    disasm-$ @ h@ $FF00 and $BD00 =  \ Flag: Loop terminates with pop { ... pc }
    or
    disasm-step
  until
  disasm-$ @  word.end !		     \ added tp
  base !
;

: see ( -- ) \ Takes name of definition and shows its contents from beginning to first ret
  ' disasm-$ !
  disasm-$ @  word.start !		     \ added tp 
  seec
  ." Bytes: "  word.end @ word.start @ - .   \ added tp
;
\ prerequisite: memstats.fs 
compiletoflash
: free ( -- ) 20 2 $1FFFF7E0 memstats ; \ STM32F103C8
compiletoram

\ Taken from mecrisp-stellaris-2.5.2/stm32f103-ra/usb-f1.txt

compiletoflash

: cornerstone ( Name ) ( -- )
  <builds begin here $3FF and while 0 h, repeat
  does>   begin dup  $3FF and while 2+   repeat
          eraseflashfrom
;

cornerstone --utils--

compiletoram
compiletoram
uptest
ticktime.

\ ------------------------------------------------------------------------------ \
\ configs.fs
\ purpose: general peripheral configuration Words


\ --------------------------------Essential First Start------------------------- \
\ compiletoram
compiletoflash

\ VERSION   
1 constant version-major
640 constant version-minor
: version ( -- c )
   ." Bluepill Diagnostics V" version-major u.ns  ." ." version-minor u.ns    \ V1.632
;

72mhz  \ for *much* faster uploading

: calltrace-handler ( -- ) \ Assume that the 2nd block of Flash isnt there and the test raised a exception.  
  ." Failed memory test. Press board RESET button to restart microprocessor " cr
  begin again	  \ Trap execution, stop the endless error message.
;

: init.calltrace ( -- )
  ['] calltrace-handler irq-fault !
;

\ ---------------------------------Configs-------------------------------------- \

\ Choose the following to paste for GPIOA, B and C
\ GPIOA_CRL (read-write) Reset:0x44444444
\  : GPIOA_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOA_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOA_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOA_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOA_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOA_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOA_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOA_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOA_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOA_CRH (read-write) Reset:0x44444444
\  : GPIOA_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOA_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOA_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOA_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOA_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOA_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOA_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOA_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ; 

\ GPIOB_CRL (read-write) Reset:0x44444444
\  : GPIOB_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOB_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOB_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOB_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOB_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOB_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOB_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOB_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOB_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOB_CRH (read-write) Reset:0x44444444
\  : GPIOB_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOB_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOB_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOB_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOB_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOB_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOB_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOB_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ;

\ GPIOC_CRL (read-write) Reset:0x44444444
\  : GPIOC_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ; 
\  : GPIOC_CRL_MODE1<< ( %bbbb -- x ) 4  lshift ; 
\  : GPIOC_CRL_MODE2<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOC_CRL_MODE3<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOC_CRL_MODE4<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOC_CRL_MODE5<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOC_CRL_MODE6<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOC_CRL_MODE7<< ( %bbbb -- x ) 28 lshift ; 
\  : GPIOC_CRL_MODE7<< ( %bbbb -- x ) 30 lshift ; 
 
\ GPIOC_CRH (read-write) Reset:0x44444444
\  : GPIOC_CRH_MODE8<<  ( %bbbb -- x ) 0  lshift ; 
\  : GPIOC_CRH_MODE9<<  ( %bbbb -- x ) 4  lshift ; 
\  : GPIOC_CRH_MODE10<< ( %bbbb -- x ) 8  lshift ; 
\  : GPIOC_CRH_MODE11<< ( %bbbb -- x ) 12 lshift ; 
\  : GPIOC_CRH_MODE12<< ( %bbbb -- x ) 16 lshift ; 
\  : GPIOC_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ; 
\  : GPIOC_CRH_MODE14<< ( %bbbb -- x ) 24 lshift ; 
\  : GPIOC_CRH_MODE15<< ( %bbbb -- x ) 28 lshift ;

\ Manual use
$40021018 constant RCC_APB2ENR

$40010800 constant GPIOA_CRL
$40010804 constant GPIOA_CRH
 
$40010C00 constant GPIOB_CRL
$40010C04 constant GPIOB_CRH
$40010C10 constant GPIOB_BSRR

$40011000 constant GPIOC_CRL 
$40011004 constant GPIOC_CRH
$40011010 constant GPIOC_BSRR

: RCC_APB2ENR_IOPAEN ( -- x addr ) 2 bit  ; \ RCC_APB2ENR_IOPAEN, I/O port A clock enable
: RCC_APB2ENR_IOPBEN ( -- x addr ) 3 bit  ; \ RCC_APB2ENR_IOPBEN, I/O port B clock enable
: RCC_APB2ENR_IOPCEN ( -- x addr ) 4 bit  ; \ I/O port C clock enable
 
: JUMPER-ON? ( --  1|0 ) 0 bit GPIOA_IDR bit@ ; \  GPIOA_IDR_IDR0?  option jumper (V3<->PA0)
: GPIOA_CRL_MODE0<< ( %bbbb -- x ) 0  lshift ;
: GPIOC_CRH_MODE13<< ( %bbbb -- x ) 20 lshift ;	\ GPIOC-13 mode
: ledon  ( -- ) 13 bit GPIOC_BSRR ! ;	\ Set bit 13 (LED)
: ledoff ( -- ) 29 bit GPIOC_BSRR ! ;	\ Reset bit 13

 \ -------------- original old style, need to be updated sometime ------------ \
 \ PA9 Open Drain
 : GPIOB_CRH_MODE9 ( %bb -- x addr ) 4 lshift GPIOB_CRH ;   
 : GPIOB_CRH_CNF9 ( %bb -- x addr ) 6 lshift GPIOB_CRH ;    
 \ 7  6  5  4
 \ CNF9  MODE9
 \ 0  1  1  0 

 : GPIOB_BSRR_BS9 ( -- ) 9 bit GPIOB_BSRR ! ;	\ GPIOB_BSRR_BS9, Set bit 9
 : GPIOB_BSRR_BR9 ( -- ) 25 bit GPIOB_BSRR ! ;	\ GPIOB_BSRR_BR9, Reset bit 9
 : PB9-LOW   GPIOB_BSRR_BR9 ;			\ Open Drain is hi-z
 : PB9-HIGH  GPIOB_BSRR_BS9 ;			\ Open Drain is short to 0v

 \ PA12 Open Drain
 : GPIOA_CRH_MODE12 ( %bb -- x addr ) 16 lshift GPIOA_CRH ; 
 : GPIOA_CRH_CNF12 ( %bb -- x addr ) 18 lshift GPIOA_CRH ;  
 \ 19 18 17 16
 \ CNF12 MODE12
 \ 0  1  1  0

 : GPIOA_BSRR_BS12 ( -- ) 12 bit GPIOA_BSRR ! ; \ GPIOA_BSRR_BS12, Set bit 12
 : GPIOA_BSRR_BR12 ( -- ) 28 bit GPIOA_BSRR ! ; \ GPIOA_BSRR_BR12, Reset bit 12
 : PA12-HIGH  GPIOA_BSRR_BR12 ; \ Open Drain !
 : PA12-LOW   GPIOA_BSRR_BS12 ; \ Open Drain !
 
\ ---------------------------Misc Programs-------------------------------------- \

: blink ( -- pc13 )
   $F GPIOC_CRH_MODE13<< GPIOC_CRH bic!		\ clear all bits
   output.od GPIOC_CRH_MODE13<<	 GPIOC_CRH bis! \ set PC13 to open drain
		  
   begin
      ledon		\ PC-13 Anode = +3.3V, Cathode = PC-13 
      1000 ms.delay 	\ accurate  1 millisecond blocking delay
      ledoff
      1000 ms.delay
   key? until		\ keep blinking until a keyboard key is pressed
;

\ ------------------------------------------------------------------------------ \
\ usb.fs
\ purpose: Usb DP low pulse for various boards

: pa12-init ( -- )	      \ Blue Pill PA12 normally HIGH = Open Drain OFF !
   %10 GPIOA_CRH_MODE12	bis!  \ output.2mhz
   pa12-high
;

: pa12-disable ( -- )
  pa12-low 
;

: pa12-pulse ( -- )  \ Blue Pill PA12 normally HIGH, pulse LOW for 10 ms
  pa12-low
\  10 ms.delay	     \ intervals are 0.1ms in this case
  pa12-low
;

: pb9-init ( -- )	   \ maple-mini normally LOW
  %10 GPIOB_CRH_MODE9 bis! \ output.2mhz
  pb9-low
;

: pb9-disable ( -- )
  pb9-low
;

: pb9-pulse ( -- )  \ maple-mini normally LOW, pulse HIGH for 1ms
  pb9-high
\  10 ms.delay	     \ = 1ms (intervals are 0.1ms)
  pb9-low
;

: usbdp-init ( -- )
  pa12-init
  pb9-init
  pb9-low
;

: usbdp-pulse ( -- )
  pa12-pulse
;

: usbdp-disable ( -- )
  pa12-disable 
  pb9-disable
  deinit.usb
;

\ ------------------------------------------------------------------------------ \
\ memtest.fs
\ purpose: all memory test words

0 variable 2nd64kb-verified-flag       \ 0 = untested or failed, 1 = passed test and has valid 2nd 64kb Flash
0 variable test-flag		       \ total memory locations that passed, should be 32768
0 variable pass-flag		       \ increment by one when a test is passed
0 variable flash=65536-declared-flag

: qty-flash-declared? ( -- bytes )	 
   $1FFFF7E0 @ $FFFF and 1024 *
;

: 2nd64kb-verified-flag-test ( -- )  
   test-flag @ 32768 - 0 = if 1 2nd64kb-verified-flag !
      else 0 2nd64kb-verified-flag !	\ 0 = untested or failed    
   then
   0 test-flag !
   pass-flag @ 1 + pass-flag !
;

: FF? ( -- )	  \ Blank check, scan $10000 to $1FFFF (65536 bytes)
   0 test-flag !				\ reset test-flag
   65535 0 do 
      $10000  i + c@ $FF = if  test-flag @ 1 + test-flag ! 
	    else $10000 i + hex. ." $FF?: " $10000 i + c@ ." $" h.2 cr
	    0 2nd64kb-verified-flag !	    \ 0 = untested or failed
	    then
   2 +loop
   2nd64kb-verified-flag-test
; 

: AA? ( --  )	  \ $AA check, scan $10000 to $1FFFF
   0 test-flag !				\ reset test-flag
   65535 0 do 
      $10000  i + c@ $AA = if  test-flag @ 1 + test-flag !
	    else $10000 i + hex. ." $AA?: " $10000 i + c@ ." $" h.2 cr
	    0 2nd64kb-verified-flag !	    \ 0 = untested or failed
	    then
   2 +loop
   2nd64kb-verified-flag-test 
; 

: 55? ( --  )	  \ $55 check, scan $10000 to $1FFFF
   0 test-flag !				\ reset test-flag
   65535 0 do 
      $10000  i + c@ $55 = if  test-flag @ 1 + test-flag !
	    else $10000 i + hex. ." $55?: " $10000 i + c@ ." $" h.2 cr
	    0 2nd64kb-verified-flag !	    \ 0 = untested or failed
	    then
   2 +loop
   2nd64kb-verified-flag-test
; 
 
: fillAA ( -- )	\ Fill $10000 to $1FFFF with $AA, 
   65535 0 do 
      %1010101010101010 $10000 i + hflash!
      \ $10000 i + hex. ." : " $10000 i + c@ h.2 cr  \ diags only
   2 +loop
   \  ." Flash with 1010101010101010 (0xAA) " cr
   ." ."				     \ visual progress dot
; 
   
: fill55 ( -- )	\ Fill $10000 to $1FFFF with $55
   65535 0 do 
      %0101010101010101 $10000 i + hflash!
   2 +loop
   \  ." Flash with 0101010101010101 (0x55) " cr
   ." ."				     \ visual progress dot
   0 2nd64kb-verified-flag !  \ reset previous pass test 
;

: erase ( -- )			       \ Erase $10000 to $1FFFF
   65535 0 do 
      $10000 i + flashpageerase
      1 ms.delay		       \ or flashpageerase won't work
      \ $10000 i + hex . decimal cr
   1024 +loop			       \ flashpageerase = Erase one 1k flash page only, no reset
   \ ." Erasing " cr
   ." ."			       \ visual progress dot
;

: 2nd64kb? ( -- )   \ Test the second 64kB flash block.    2nd64kb-verified-flag @ . 
   0 2nd64kb-verified-flag !  \ 0 = untested or failed, 1 = passed test and has valid 2nd 64kb Flash
      ." ."    \ first visual progress dot   
      erase    \ erase everything
      FF?      \ $FF check, test #1
      fillAA   \ fill all locations with %1010101010101010  ($AA)
      AA?      \ $AA check, test #2
      erase    \ erase before next test
      FF?      \ $FF check, test #3
      fill55   \ fill all locations with %0101010101010101  ($55)
      55?      \ $55 check, test #4
      erase    \ leave flash in erased state
      FF?      \ $FF check, test #5
      pass-flag @ 5 = if  1 2nd64kb-verified-flag !
	 else 0 2nd64kb-verified-flag !
	 then
      0 pass-flag !
;
 
: hidden64kB? ( -- )  
    2nd64kb-verified-flag @ if ." Hidden second 64kB Flash block VERIFIED, total of 128kB Flash in this MCU "
	       else ." Potential hidden second 64kB Flash block: untested or failed. "
	       then cr
;
 
: cause-exception ( -- )
   1000000 @ .
;

: wait ( -- )
   ." Please wait, testing Flash " 
; 
 
: flash-declared? ( -- )
  qty-flash-declared?
  65536 =
  IF
    1 flash=65536-declared-flag !
  ELSE
    0  flash=65536-declared-flag !
  THEN
;

: print-flash-declared ( -- )
  qty-flash-declared? . ." flash is declared in the Flash size register at 0x1FFFF7E0 " cr
;
\ ------------------------------------------------------------------------------ \
\ cpuid.fs
\ purpose: all mcu identification words

0 variable DBGMCU_IDCODE-UNREADABLE-FLAG

: 3addr ( -- )			       \ Device ID register addresses Bytes: 30 ok.
   $1FFFF7E8 @ $1FFFF7EC @ $1FFFF7F0 @
;

: duid ( addr1 addr2 addr3 -- u )      \ Derived device ID.  Device ID Bytes: 28 ok.
  3 1 do xor loop ;

: serial ( -- ) 3addr duid ." Unique Serial Number = 0x" hex. cr ;

: is-ascii? ( u -- true = printable | no = . )  \ Bytes: 58 ok.
  >r
  r@ 32 u>= r@ 127 u<
  and if
     r> emit
     else
     [char] . emit rdrop
  then ;

: ascii. ( -- )
  dup $ff000000 and 24 rshift is-ascii?  \ split Bytes: 60 ok.
  dup $00ff0000 and 16 rshift is-ascii? 
  dup $0000ff00 and  8 rshift is-ascii?
  $000000ff and is-ascii?
;
 
: id ( u -- )				  \ Bytes: 96
  dup ." $" hex. ." |"			  \ legend
  dup $ff000000 and 24 rshift is-ascii?	  \ split
  dup $00ff0000 and 16 rshift is-ascii? 
  dup $0000ff00 and  8 rshift is-ascii?
  $000000ff and is-ascii?
  ." | "
;

: scb_cpuid-bits31-0 ( -- )  \ scb_cpuid = $E000ED00
  scb_cpuid @ dup
  ." $" hex. ." = "
  $411FC231 = if ." STM32F1 series" else ." NOT STM32F1 series"
  then 
;

: scb_cpuid-bits31:24 ( -- )
  scb_cpuid @ $ff000000 and 24 rshift
;

: scb_cpuid-bits23:20 ( -- )
  scb_cpuid @ $00f00000 and 20 rshift
;

: scb_cpuid-bits19:16 ( -- )
  scb_cpuid @ $000f0000 and 16 rshift
;

: scb_cpuid-bits15:4 ( -- )
  scb_cpuid @ $0000fff0 and 4 rshift
;

: scb_cpuid-bits3:0 ( -- )
  scb_cpuid @ $0000000f and 
; 

: scb-cpuid ( -- )
   ." SCB-CPUID: " cr
   ." ---------- " cr
   ." <BITS-31:24>" scb_cpuid-bits31:24 ." $" h.2 ." </BITS-31:24>" cr
   ." <BITS-23:20>" scb_cpuid-bits23:20 ." $"  h.1 ."  </BITS-23:20>" cr
   ." <BITS-19:16>" scb_cpuid-bits19:16 ." $"  h.1 ."  </BITS-19:16>" cr
   ." <BITS-15:4>"  scb_cpuid-bits15:4 ." $"  h.3 ."  </BITS-15:4>" cr
   ." <BITS-3:0>"   scb_cpuid-bits3:0 ." $"  h.1 ."  </BITS-3:0>" cr
;

: uuid ( -- )	  \  unique-device-id
 ." UNIQUE DEVICE ID: " cr
 ." ----------------- " cr
 ." BITS-95:64 | " $1FFFF7F0 @ dup ." 0x" hex. ." | " ascii. cr
 ." BITS-63:32 | " $1FFFF7EC @ dup ." 0x" hex. ." | " ascii. cr
 ." BITS-31:0  | " $1FFFF7E8 @ dup ." 0x" hex. ." | " ascii. cr
 cr
;


: print-dbgmcu_idcode ( -- )
   $E0042000 @ ." DBGMCU_IDCODE [@ 0xE0042000] = 0x" hex. cr
;

: dbgmcu_idcode? ( -- ) \ 1 if DBGMCU_IDCODE NOT READABLE - pass
   $E0042000 @  0 =
   IF 
     1  DBGMCU_IDCODE-UNREADABLE-FLAG !
   ELSE
     0  DBGMCU_IDCODE-UNREADABLE-FLAG !
   THEN
;

$E00FFFD0 constant jdec-cont
$E00FFFE0 constant jdec-id
0 variable jdec-verified-flag

: jdec_ident_code ( -- hex )   \ jdec Identity Code
  jdec-id cell+ c@ $f0 and 4 rshift
  jdec-id 2 cells + c@ $7 and  
  4 lshift or 
;

: jdec_cont_code ( -- c ) jdec-cont c@ ; \ jdec Continuation Code

: jdec-verified-flag? ( -- )
   jdec_ident_code $20 =
   swap
   jdec_cont_code  $00 =
   and
   IF	 1 jdec-verified-flag !
   ELSE  0 jdec-verified-flag !
   THEN
;

: jdec-fallthru ." JDEC manufacturer id: UNKNOWN, consult readme 'JDEC Codes' table" cr ;

: jedec_id. ( addr -- x )	    \ jdec print 
   jdec_cont_code dup ." Jdec Continuation Code: 0x" hex.2 cr
   jdec_ident_code dup  ." Jdec Identity Code: 0x" hex.2 cr
   8 lshift +							  \ merge ident/cont into one number for case
   case
      $2000 of ." JDEC manufacturer id: STMicroelectronics "   endof \ ident/cont
      $3b04 of ." JDEC manufacturer id: CKS or APM "	       endof
      $C807 of ." GigaDevice Semiconductor "		       endof
      $5107 of ." GigaDevice Semiconductor (Beijing)"	       endof
      		       
      jdec-fallthru swap
   endcase
;

\ flash=65536-test		 = 1 if flash=65536 - pass
\ DBGMCU_IDCODE-UNREADABLE-FLAG	 = 1 if DBGMCU_IDCODE NOT READABLE - pass
\ 2nd64kb-verified-flag		 = 1 if 2nd64kb-verified - pass
\ jdec-verified-flag		 = 1 if STMicroelectronics - pass

: test-status? ( -- )
   flash=65536-declared-flag @ 0 = IF ." FAIL - Declared flash not 65536 "
      ELSE ." PASS - Declared flash = 65536 Bytes " THEN cr
   DBGMCU_IDCODE-UNREADABLE-FLAG @ 0 = IF ." FAIL - DBGMCU_IDCODE is readable with no SWD/Jtag connected "
      ELSE ." PASS - DBGMCU_IDCODE is NOT readable without SWD/Jtag connected " THEN cr
   2nd64kb-verified-flag @ 0 = IF ." FAIL - Second 64KB flash block not verified or not tested. Have you run Menu item [h] ? "
      ELSE ." PASS - Second 64KB flash block verified "  THEN cr
   jdec-verified-flag @ 0 = IF ." FAIL - JDEC manufacturer id NOT STMicroelectronics " 
      ELSE ." PASS - JDEC manufacturer id IS STMicroelectronics " THEN cr
; 

: F103C8T6-Auth? ( -- )
   dbgmcu_idcode?
   flash-declared?
   jdec-verified-flag?
   flash=65536-declared-flag @  
   DBGMCU_IDCODE-UNREADABLE-FLAG @ 
   2nd64kb-verified-flag @
   jdec-verified-flag @
   and and and
   IF    ." STM32F103C8 authentication PASSED all these tests:" cr 
   ELSE  ." STM32F103C8 authentication FAILED one or more tests: " cr
   THEN
         ." ---------------------------------------------------- " cr
   test-status? 
;
\ ------------------------------------------------------------------------------ \
\ menu.fs
\ purpose: menues and help texts

: 0dump $00000  65535 dump ;	 \ $0 to $FFFF, 1st 64kB Flash block
: 1dump $10000  65535 dump ;	 \ $10000 to $1FFFF, 2nd 64kB Flash block
: fflag-fail! $fff0 $1FFF0 hflash! ;
: fflag-pass! $ff00 $1FFF0 hflash! ;	 
: ex3   $20000  dump16 ;	       \ Testing only: generate exception #3 
: flash-$55@$1FFF0 %0101010101010101   \ Testing only: Fail menu [h] : insert 55 @$1FFD0 near end of 128kb block
 $1FFF0 hflash! ;
: read-@$1FFF0 $1FFF0 c@ h.2 cr ;      \ Testing only, verify insert 55 @$1FFD0 worked.


: credits ( -- ) cr cr
   ." Bluepill Diagnostics (usb/swdcom) written by Terry Porter <techman001@protonmail.com> " cr
   ." https://mecrisp-stellaris-folkdoc.sourceforge.io/bluepill-diagnostics-v1.6.html " cr
   ." Mecrisp-Stellaris Forth Homepage: http://mecrisp.sourceforge.net/ " cr
   ." Mecrisp-Stellaris created by Matthias Koch  " cr
;

: license ( -- ) cr cr
   ." This project is licensed under the terms of the GPL3 license " cr 
;

: faq ( -- ) cr cr
   ." * How many times can the [h] test be safely run ? << Thousands of times " cr
   ." * The Flash Data View is too fast  << Use your terminal loging facility & capture it " cr
   ." * Will this test harm my chip ? << No " cr
   ." * How can I view the current chip memory status ? << Quit the menu and enter 'free' " cr
   ." * How was the Test Kit made ? << Using the Forth Programming Language " cr
   ." * How do I see other programs on the chip ?  << Quit the menu and enter 'words4' " cr
   ." * Can I write other programs on this chip  << Yes, it's a complete Forth system " cr
   ." * Learn more about Forth << Mecrisp Stellaris Unofficial UserDoc: https://mecrisp-stellaris-folkdoc.sourceforge.io " cr
;

: usb-faq ( -- ) cr cr
   ." BluePill and generic boards: USBDP on GPIO-A12, normally HIGH pulsed LOW for 10mS at reboot " cr
   ." Maplemini: USBDP on GPIO-B9, normally LOW, pulsed HIGH for 10mS at reboot " cr
;

: fallthru ." Not a menu item: press the 'm' key for the menu" cr 0 ;

: extra-menu-print ( -- ) cr cr
  ." ---------- " cr 
  ." Extra Menu " cr
  ." ---------- " cr
  ." f - view First  64kb flash memory block: 0x00000 - 0x10000 " cr
  ." s - view Second 64kb flash memory block: 0x10000 - 0x1FFFF " cr
  ." i - unique device Id " cr
  ." n - unique derived serial Number " cr
  ." a - fAQ " cr
  ." u - Usb faq " cr
  ." c - Credits " cr
  ." q - Quit back to main menu " cr
  ." m - Extra menu " cr
  cr cr
;

: menu-a ( -- )
   qty-flash-declared?
   case 
      65536  of ." h - test for Hidden second 64kb flash block: 0x10000 - 0x1FFFF" endof
      131072 of ." h - test second Half of the 128KB flash declared for this chip" endof
	        ." unexpected result "
   endcase
   2nd64kb-verified-flag @ if ." :  PASSED " then cr     
;

: menu-print ( -- ) cr cr 
 ." =========================================== " cr
 ." Bluepill Diagnostics V" version-major u.ns  ." ." version-minor u.ns  ."  - GPL3 Licensed" cr
 ." =========================================== " cr 
 menu-a	 \ flash test menu
 ." f - how much Flash is declared in the Flash Size Register ? " cr
 ." d - Print DBGMCU_IDCODE " cr
 ." a - STM32F103C8T6 Authenticity test, don't use with SWD/JTAG. " cr
 ." j - Jdec manufacturer id " cr
 ." e - Extra menu " cr
 ." q - Quit menu, enter the Forth command line " cr
 ." m - Main menu " cr
 cr cr
;

: extra-menu ( -- )  cr \ Extra Menu
  extra-menu-print
  begin key
     case
   	 [char] a of faq      extra-menu-print  0 endof
 	 [char] c of credits  extra-menu-print  0 endof
 	 [char] f of 0dump    extra-menu-print  0 endof
 	 [char] s of 1dump    extra-menu-print  0 endof
 	 [char] i of uuid     extra-menu-print  0 endof
	 [char] n of serial   extra-menu-print  0 endof
	 [char] u of usb-faq  extra-menu-print  0 endof
	 [char] m of	      extra-menu-print  0 endof
	 [char] q of				1 endof
	 fallthru swap		 \ default fall thru	  
     endcase
  until
  menu-print
;

: menu ( -- ) cr			 \ Main Menu
   menu-print
   begin key
      case
	 [char] d of print-dbgmcu_idcode     menu-print  0 endof
	 [char] f of print-flash-declared    menu-print  0 endof
	 [char] a of F103C8T6-Auth?	     menu-print  0 endof
	 [char] j of jedec_id.		     menu-print  0 endof
	 [char] e of extra-menu				 0 endof
	 [char] h of wait 2nd64kb?	     menu-print  0 endof
	 [char] m of			     menu-print  0 endof
	 [char] q of					 1 endof
	 fallthru swap	\ default fall thru
      endcase  
   until
   cr cr
   ." enter 'menu' to restart menu " cr
;

: m menu ( -- ) ;

\ Program Name: id.fs
\ Copyright 2022 by t.j.porter , GPL licensed.
\ For Mecrisp-Stellaris by Matthias Koch.
\ https://sourceforge.net/projects/mecrisp/
\ Chip: STM32F103C8 or clones.
\ All register names are CMSIS-SVD compliant
\ Note: gpio a,b,c,d,e, and uart1 are enabled by Mecrisp-Stellaris Core.
\ Standalone: no preloaded support files required
\
\ This Program : Determines if a genuine STM32F103C8T6 is present, prints all the ID registers of Blue Pill MCU
\
\ *** NOTE *** 64KB Image MUST be flashed with /usr/local/share/openocd/scripts/target/stm32f1x.cfg or
\ 2nd flash block test will FAIL with "Wrong address or data for writing flash !!" !!
\
\ Clock is set to 72MHz in $(LIB)72mhz-f103.fs for faster LIB uploading
\ -------------------------------------------------------------------------------------------------- \


: option-jumper? ( -- )	  \ Two pin option jumper selects whether the terminal will use SWD or USB at power up.
   $F GPIOA_CRL_MODE0<<	 GPIOA_CRL bic!   \ clear all bits
   INPUT.PULLX GPIOA_CRL_MODE0<<	  \ set input pullup/pull down mode. Is pulldown when ODR bit = 0 (reboot default)
                  GPIOA_CRL bis!
   JUMPER-ON? not IF init.usb menu	  \ (3V<->PA0) JUMPER-ON? then PA0 = HI = SWDCOM, else USB after reboot.
      THEN				  \ else USB and menu after reboot.  
;

: init ( -- )
   72mhz
   7200 1 - init.systick  \ tick = 1 ms needed for usb pulse ?
   init.calltrace
   RCC_APB2ENR_IOPAEN RCC_APB2ENR_IOPBEN RCC_APB2ENR_IOPCEN + + $40021018 bis!  \ enable GPIO's A,B & C
   usbdp-init 
   usbdp-pulse 
   option-jumper?
   cr cr cr
   drop			   \ Workaround for '42' INIT bug, only occurs after reset
;	 


compiletoram