Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;this is forth85_48 Aim. Continue with timing of forth words.
- ;Had problems with clrbit not working. Traced after long while to it sitting in the dictionary
- ; on a boundary in flash ending with 00 and with padding byte. Combination made xxff cycle to xx00
- ; without changing msbyte because I coded a brcc instead of a brne. Hard to trace. Yay for avrstudio.
- ;Did not address issues below.
- ;Keep slimming.
- ;Also test how useful TCNT0 is now that it's being used by usi serial.
- ;.equ testing = 1 ;Very handy. Used a lot in AVR Studio4; makes io verbose. comment out later
- ;.equ livetesting = 1 ;Very handy when live; comment out to take out the little dumps and diagnostics.
- .NOLIST
- .include "tn85def.inc"
- .LIST
- .include "macros.asm"
- .include "blockdefs.asm"
- ;---------------------------------------------------
- .def mylatest =r2 ;r2,r3 is mylatest
- .def myhere =r4 ;r4,r5 is myhere. The pointer to flash copy in buf2.
- .def SOFPG=r6 ;start of flash page
- ;r6,r7 byte adr of flash page (11c0)
- ;r8,r9 (0012) offset when flash comes into buf2. r8 +E0 = myhere
- .def SECONDLETTER =r10 ;helpful for debugging
- .def FOUNDCOUNTER = r11 ;dealWithWord clicks this if found =1. Counts successful finds in dictionary.
- .def STATE = r12
- .def STOP = r13 ;stop interpreting line of words
- .def BOTTOM = r14 ;have hit the bottom of the dict and not found a match
- .def FOUND = r15 ;if found=1 we have a match of Ram word on dictionary
- .def spmcsr_val=r18
- .def buf_ctr =r19 ;for flash section
- ;r20 is length of word in WORD
- ;r21 is the flash length of word with immediate bit 8, if any, still there
- .def vl = r22
- .def vh = r23 ; u,v,w,x,y,z are all pointers
- .def wl = r24 ;w=r24,25
- .def wh = r25
- .equ TX_PIN = 1 ;0 !!
- .equ RX_PIN = 0 ;2 ; Tx,Rx pins are PB0 and PB2 resp
- .def serialByteReg = r16
- .def rxByte = r18
- .def counterReg = r17
- ;---------------------------------------------------------------
- .eseg
- .org $10
- .dw HERE, LATEST , $01a0 ;these should be burned into tn85 with code
- ;--------------------------------------------------------------------
- .DSEG
- .ORG 0x60
- .equ BUF1LENGTH = 128
- .equ eHERE = $0010 ;eeprom adr of system varial eHere
- .equ eLATEST = $0012
- .equ eVar = $0014 ;holds next ram adr for next var declaration
- buf1: .byte BUF1LENGTH ;input buffer. Lines max about 125
- buf2: .byte BUF1LENGTH ;this fits two flash buffers
- buf3: .byte 64 ;new for 5.8.14 Allows 3rd flash page. And 128 byte input buffer,buf1
- ;So buf1=060..0df,buf2=0e0..15f,buf3= 160..19f
- ;varspace=1a0..1df,mystack=1e0..ret stack space that ends at 25f (128 bytes for both stacks)
- varSpace: .byte 64 ;might need more than 32 variables
- myStackStart: .byte 64 ;currently at $1E0.Meets return stack.
- ;---------------------------------------------------------------------------------
- ;---------------------------------------------------------------------------------
- .CSEG
- .ORG 0x800 ;dictionary starts at 4K (2K words) mark
- ;----------------------------------------------------
- one_1:
- .db 0,0,3, "one" ;code for one
- one:
- ; rcall stackme
- rcall stackme_2
- .db 01, 00
- ret
- ;----------------------------------------------
- two_1:
- header one_1, 3, "two"
- two:
- rcall stackme_2
- .db 02,00
- ret
- ;------------------------------------------
- dup_1:
- header two_1,3,"dup"
- dup:
- mypop r17
- mypop r16
- mypush r16
- mypush r17
- mypush r16
- mypush r17
- ret
- ;-------------------------------------------
- drop_1:
- header dup_1,4,"drop"
- drop:
- mypop r17
- mypop r16 ;TODO what if stack pointer goes thru floor?
- ret
- ;----------------------------------
- swapp_1: ;twp p's becasue assembler recognizes avr opcode swap
- header drop_1,4, "swap" ;rcall swapp but otherwise it's "swap"
- swapp:
- mypop2 r17,r16
- mypop2 r19,r18
- mypush2 r16,r17
- mypush2 r18,r19
- ret
- ;-------------------------------------------------
- ;shift this later
- S_1:
- ;the EOL token that gets put into end of buf1 to stop parsing
- header swapp_1,$81,"S" ;NB always immediate
- S: ldi r16,02
- mov BOTTOM,r16 ;r14 =2 means a nice stop. EOL without errors
- clr STOP
- inc STOP ;set time-to-quit flag
- takemeout 's'
- ret
- ;------------------------------------------
- fetch_1: ;doesn't like label = @-1
- ;classic fetch. (adr -- num). Only in RAM
- header S_1,1,"@"
- fetch:
- pushx ;going to use x to point so better save
- mypop xh
- mypop xl
- ld r16,x+
- ld r17,x
- mypush r16
- mypush r17 ; and put them on my stack
- popx ;return with x intact and RAM val on my stack
- ret
- ;dddddddddddddddddddddddddddddddddddddddddddddddd
- cfetch_1: ;doesn't like label = c@-1
- ;classic fetch. (adr -- num). Only in RAM. Do I want y to advance just one byte on mystack
- header fetch_1,2,"c@"
- cfetch:
- pushx ;going to use x to point so better save
- mypop xh
- mypop xl
- ld r16,x+
- mypush r16
- clr r16
- mypush r16 ;so we get a 16 bit val on stack
- popx ;return with x intact and RAM val on my stack
- ret
- ;dddddddddddddddddddddddddddddddddddddddddddddddd
- store_1: ;classic != "store"(num adr --) . Num is now at cell adr.
- header cfetch_1,1,"!"
- store:
- pushx
- mypop2 xh,xl ;there goes the address
- mypop2 r17,r16 ;there goes the num
- st x+,r16
- st x,r17 ;num goes to cell with location=adr
- popx
- ret
- ;ddddddddddddddddddddddddddddddddddddddddddddddddddd
- cstore_1: ;classic c!= "store"(16bit adr --) . Lower 8 bits Num is now at cell adr.
- header store_1,2,"c!"
- cstore:
- pushx
- mypop2 xh,xl ;there goes the address
- mypop r17 ;there's the high byte. Thrown away
- mypop r16 ;there goes the num. Just 8 bits at this stage.
- st x+,r16
- ; st x,r17 ;num goes to cell with location=adr
- popx
- ret
- ;------------------------------------
- star_1: ;classic 16*16 mulitply (n n -- n*n)
- header cstore_1,1,"*"
- star:
- mypop2 r17,r16
- mypop2 r19,r18 ;now have both numbers in r16..r19
- rcall mpy16s ; multiply them. Result in r18..r21. Overflow in r20,21
- mypush2 r18,r19
- ret
- ;-----------------------------------------
- slashMod_1: ;classic /MOD (n m -- n/m rem)
- header star_1,4,"/mod"
- slashMod:
- push r13
- push r14 ;this is STOP but is used by div16s, so better save it
- mypop2 r19,r18 ; that's m
- mypop2 r17,r16 ;that's n
- rcall div16s ;the the 16 by 16 bit divsion
- mypush2 r16,r17 ;answer ie n/m
- mypush2 r14,r15 ;remainder
- pop r14
- pop r13
- ret
- ;dddddddddddddddddddddddddddddddddddddddddddd
- plus_1: ;classic + ( n n -- n+n)
- header slashMod_1,1,"+"
- plus:
- mypop2 r17,r16
- mypop2 r19,r18
- clc
- add r16,r18
- adc r17,r19
- mypush2 r16,r17
- ret
- ;--
- minus_1: ;classic - ( n m -- n-m)
- header plus_1,1,"-"
- minus:
- mypop2 r19,r18
- mypop2 r17,r16
- clc
- sub r16,r18
- sbc r17,r19
- mypush2 r16,r17
- ret
- ;dddddddddddddddddddddddddddddddddddddddddd
- ;first need store system vars in the eeprom. Arbitrarily 0010 is HERE and 0012 (in eeprom) is LATEST
- ;----------------------------------------
- percentcstore_1: ;(n16 adr16 --) %c! stores stack val LSbyte to eeprom adr
- ; eg 1234 10 00 stores 34 to 0010 <--eeprom adr
- header minus_1,3,"ec!" ;relink to minus_1. Jmp over first port words
- percentcstore:
- mypopb ;adr in r18,19
- mypopa ;data. Lower byte into r16
- rcall eewritebyte ;burn it into eeprom
- ret
- ;----------------------------------
- percentstore_1: ; (n16 adr16 --) b16 stored at eeprom adr adr16 and adr16+1
- header percentcstore_1,2, "e!" ;changed %! to e! PB!!
- percentstore:
- estore: ;TODO refer to this as e! only
- mypopb ;adr in b=r18,19
- mypopa ;n16 into r16,17 as data
- rcall eewritebyte ;burn low data byte
- clc
- inc r18
- brne outpcs
- inc r17 ;sets up adr+1 for next byte
- outpcs:
- mov r16,r17 ;r16 now conatins hi byte
- rcall eewritebyte
- ret
- ;-------------------------------
- ;11:36 a.m. Sunday, 2 November 2014. Seems the ec@ just puts one 8bit char on the stack. This is
- ;a bit of a problem eg when working at the terminal (how to print just TOS 8bits)
- ;work around, leave for the time being. TODO
- percentcfetch_1: ;(eepromadr16--char). Fetch eeprom byte at adr on stack
- header percentstore_1,3,"ec@"
- percentcfetch:
- mypopb ;adr now in r18,19
- rcall eereadbyte
- mypush r16 ; there's the char going on stack. Should be n16? Not n8?
- ; clr r16
- ; mypush r16 ;!! wont allow compile now there's a 0 in the high byte
- ret
- ;-------------------
- percentfetch_1: ;(adr16--n16) get 16bits at adr and adr+1
- header percentcfetch_1,2,"e@" ;PB!! changed from %@
- percentfetch:
- push r18 ;PB!! careful
- rcall percentcfetch ;low byte now on stack. TODO test this with better percentcfetch
- inc r18
- brcc downpf
- inc r19
- downpf:
- rcall eereadbyte ;there's the high byte hitting the mystack
- mypush r16
- pop r18 ;!! ditto
- ret
- ;-------------------------------
- gethere_1: ; leaves current value of eHERE on stack
- header percentfetch_1,7,"gethere"
- gethere:
- rcall stackme_2
- .dw eHere
- rcall percentfetch
- ret
- ;--------------------
- getlatest_1: ;leaves current value of latest on stack
- header gethere_1,9, "getlatest"
- getlatest:
- rcall stackme_2
- .dw eLATEST ;the address of the latest link lives in eeprom at address 0012
- rcall percentfetch ;get the val out of eeprom
- ret
- ;------------------
- colon_1: ;classic ":"compiling new word marker
- header getlatest_1,1,":"
- rcall coloncode
- ret
- ;----------------------------------------
- comma_1: ;classic comma. ;Put adr on stack into dictionary at myhere and bump myhere
- header colon_1,1,","
- comma:
- mypopa ;adr now in r16,17
- pushz ;save z
- movw zl,myhere ;z now pnts to next avail space in dic
- st z+,r16
- st z+,r17
- movw myhere,zl ;so that myhere is updated as ptr
- popz ;bring z back
- ret
- ;------------------------------------
- tic_1: ;clasic tic('). Put cfa of next word on stack
- header comma_1,1, "'"
- tic:
- rcall word ;point to next word in input
- rcall findword ;leaving cfa in z
- mypush2 zl,zh
- rcall two ;but it's in bytes. Need words so / by 2
- rcall slashmod
- rcall drop ;that's the remainder dropped
- ;now have cfa of word after ' on stack in word-units.
- ret
- ;-----------------------
- dummy_1: ;handy debugging place to put a break point
- header tic_1,$85,"dummy" ;first immediate word. TODO take out. Not much space gained.
- dummy:
- nop
- nop
- nop
- ret
- ;--------------------------------
- compstackme_2_1: ;needed infront of every number compiled
- header dummy_1, $0d,"compstackme_2"
- compstackme_2:
- ldi r16,low(stackme_2)
- ldi r17,high(stackme_2)
- mypush2 r16,r17 ;in words need to *2 to convert to bytes
- rcall two
- rcall star
- rcall compileme
- ret
- ;-----------------------------------------
- double_1: ;whatever's on stack gets doubled. Usful words-->bytes. (n...2*n)
- header compstackme_2_1, 6, "double"
- double:
- mypopa ;stk to r16,17
- clc ;going to do shifts
- rol r16
- rol r17 ;r16,17 now doubled
- mypush2 r16,r17
- ret ;with 2*n on my stk
- ;--------------------------------------
- semi_1: ;classic ";". Immediate TODO compile a final ret
- header double_1,$81,";"
- semi:
- nop
- rcall insertret ;compile ret
- ;rcall oneBitTime
- rcall delay100ms ;trying some waits to give spm time
- rcall burnbuf2and3
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- ;rcall oneBitTime ;ditto
- ;rcall oneBitTime ;ditto. Seems to be working. eeprom writes wreck spm's.
- rcall rbrac ;after semi w'got back to executing
- ; rcall updatevars ;update HERE and LATEST in eeprom
- rcall updatevars2 ;Better version. update HERE and LATEST in eeprom
- ret
- ;---------------------------------------
- rbrac_1: ;classic "]" ,immediate
- header semi_1,$81,"]"
- rbrac:
- clr STATE ;go to executing
- ret
- ;------------------------------------------------
- immediate_1: ;classic IMMEDIATE. Redo len byte so MSbit =1
- header rbrac_1,$89,"immediate"
- immediate:
- mypush2 r2,r3 ;this is mylatest. pnts to link of new word
- rcall two
- rcall plus ;jmp over link to pnt to len byte
- pushx ;better save x
- mypop2 xh,xl ;x now pnts to len byte
- ld r16,x ; and put it into r6
- ldi r18,$80 ;mask
- or r16,r18 ;eg 03 --> 83 in hex
- st x,r16 ;put len byte back
- popx ;back where it was
- ret ;done now newly created word is immediate
- ;-------------------------------------------------
- emit_1: ;(n8 --) classic emit
- header immediate_1, 4, "emit"
- emit:
- rcall emitcode
- ret
- ;--------------------------------------
- zero_1: ;stack a zero
- header emit_1,4,"zero" ;new link to emit
- zero:
- rcall stackme_2
- .db 0,0
- ret
- ;----------------------------------------
- equal_1: ;(n1 n2 -- flag)
- header zero_1,1,"="
- equal:
- rcall equalcode
- ret
- ;----------------------------------------
- zeroequal_1: ;(n -- flag)
- header equal_1,2,"0="
- zeroequal:
- rcall zero
- rcall equal
- ret
- ;-------------------------
- oneplus_1: ;(n--n+!) adds one to what's on stack
- header zeroequal_1, 2,"1+"
- oneplus:
- rcall one
- rcall plus
- ret
- ;==============inserted 1+ here=============
- inc_1: ;( var --) incr the var on stk;from : inc dup @ 1+ swap ! ;
- header oneplus_1,3,"inc"
- incc:
- rcall dup
- rcall fetch
- rcall oneplus
- rcall swapp
- rcall store
- ret
- ;==========inserted inc here ---------------------
- over_1: ;(n1 n2 --n1 n2 n1)
- header inc_1,4,"over"
- over:
- mypopa
- mypopb
- mypush2 r18,r19 ;n1
- mypush2 r16,r17 ;n2
- mypush2 r18,r19 ;n1. so end up with (n1,n2,n1
- ret
- ;-----------------------------------
- rot_1: ;classic (n1 n2 n3 -- n2 n3 n1)
- header over_1,3,"rot"
- rot:
- mypopa
- push r17
- push r16 ;save n3
- rcall swapp ; n2 n1
- pop r16
- pop r17
- mypush2 r16,r17 ;n2 n1 n3
- rcall swapp ;n2 n3 n1
- ret
- ;------------------------------------
- reverse3_1: ;PB (n1 n2 n3 -- n3 n2 n1). Reverses top 3 order
- header rot_1,8,"reverse3"
- reverse3:
- rcall swapp ; n1 n3 n2
- rcall rot ; n3 n2 n1
- ret ;so (n1 n2 n3 -- n3 n2 n1)
- ;--------------------------------------------
- unrot_1: ;PB (n1 n2 n3 -- n3 n1 n2) Buries topitem two down
- header reverse3_1,5,"unrot"
- unrot:
- rcall reverse3 ; (n1 n2 n3 -- n3 n2 n1)
- rcall swapp ; n3 n1 n2
- ret
- ;--------------------------------
- andd_1: ;classic AND
- header unrot_1,4,"andd" ; two d's otherwise asm problems
- andd:
- mypopa
- mypopb
- and r16,r18
- and r17,r19
- mypush2 r16,r17
- ret
- ;----------------------------------------
- orr_1: ;classic OR
- header andd_1,3,"orr" ; two r's otherwise asm problems
- orr:
- mypopa
- mypopb
- or r16,r18
- or r17,r19
- mypush2 r16,r17
- ret
- ;------------------------
- calcjump_1: ;(to from -- opcode)
- header orr_1,$88, "calcjump"
- calcjump:
- rcall calcjumpcode
- ret ;with opcode on stack
- ;-----------------------
- begin_1: ;( -- adr) classic BEGIN. Used in most loops
- header calcjump_1,$85,"begin"
- begin:
- rcall stackmyhere ;put next adr on stack. For AGAIN etc
- ret ;with adr on stack
- ;---------------------------
- again_1: ; (to_adr -- ) classic AGAIN cts loop back to BEGIN
- header begin_1, $85,"again"
- again:
- rcall stackmyhere ; to_adr fr_adr
- rcall minus ;rel_adr_distance eg $ffdd
- rcall stackme_2
- .dw $0002
- rcall div ;now adr difference in words. Works better.
- rcall stackme_2
- .dw $0fff ;$ffdd $0fff
- rcall andd ;$0fdd eg.
- rcall stackme_2
- .dw $c000 ;$0fdd $c000
- rcall orr ;$cffdd = rjmp back_to_again
- rcall one
- rcall minus ;t0-fr-1 = the jump part of rjmp
- rcall comma ;insert into dic
- ret ;with rjmp opcode in next pos in dic
- ;------------------------------
- div_1: ; (n1 n2 -- n1/n2) classic / Could make 2 / faster with >, one right shift
- header again_1,1,"/"
- div:
- rcall slashMod
- rcall drop
- ret
- ;---------------------------------
- halve_1: ; (n -- n/2) use shifts to halve num on stack. Handy
- header div_1,5,"halve"
- halve:
- mypopa
- clc
- ror r17
- ror r16
- mypush2 r16,r17 ;now num on stack has been halved
- ret ;with n/2 on stk
- ;--------------------
- OK_1: ;classic "ok"
- header halve_1,2,"OK" ;relink with halve_1
- OK:
- ldi r16,'K'
- ldi r17,'O'
- clr r18
- mypush2 r16,r18 ;16bits K
- mypush2 r17,r18 ;'O'
- rcall emitcode
- rcall emitcode
- ldi r16,'}' ;try this for a cursor prompt
- clr r18
- mypush2 r16,r18
- rcall emitcode
- ret ;after having emitted "OK" to terminal
- ;-------------------------------
- CR_1: ;output a carriage return. Need $0d too?
- header OK_1,2, "CR"
- CR:
- ldi r16,$0d
- mypush r16
- clr r16
- mypush r16 ;all stack items are 16bits
- rcall emitcode
- ret ;after sending CR to terminal
- ;--------------------------
- test1_1: ;just need some dic word to try with new serialFill
- header CR_1,5,"test1"
- test1:
- ldi serialByteReg, '*'
- rcall sendSerialByte
- ldi serialByteReg, 'T'
- rcall sendSerialByte
- ldi serialByteReg, 'T'
- rcall sendSerialByte
- ldi serialByteReg, '*'
- rcall sendSerialByte
- inc r1
- inc r1 ;TESTING take out later TODO
- ret
- ;-------------------------------------------------------
- dotS_1: ;classic .S Prints stack items nondestructively
- header test1_1,2,".S"
- dotS:
- rcall dotScode ;TODO check there is *something* on the stack first
- ret
- ;----------------------------------------------------------
- dot_1: ;( n16 -- ) classic "." that prints the num on the TOS
- header dotS_1,1,"."
- dot:
- push r16
- push r17
- mypopa ;TO_stk --> r16r17
- rcall d1617 ;print it
- pop r17
- pop r16
- ret
- ;-----------------------------
- Sdot_1: ;( adr16 len16 --) classic S" Prints string from flash
- header dot_1,2,"S."
- Sdot:
- push r16
- push r17
- push r18
- ; pushz
- mypopb ;r18 = len
- mypop2 zh,zl ;x gets the adr in flash of the string
- upsd:
- lpm r16,z+ ;get byte from flash
- rcall sendserialbyte
- ;rcall d16
- dec r18
- brne upsd ;do this for len times
- ; popz
- pop r18
- pop r17
- pop r16
- ret
- ;----------------------------------------
- words_1: ;classic words. All words get printed out tot the terminal.
- header Sdot_1,5,"words"
- words:
- rcall wordscode
- ret
- ;---------------------------------------
- getvarptr_1: ;leaves current value of varptr stack
- header words_1,9, "getvarptr"
- getvarptr:
- rcall stackme_2
- .dw eVar ;the address of the latest link lives in eeprom at address 0012
- rcall percentfetch ;get the val out of eeprom
- ret ;with next avaialble adr for variable on stack. Lives in buf just below mystack
- ;-----------------------------------------------
- hereadr_1: ;classic here. Puts adr of eHere on stack. Currently 010 in eeprom
- header getvarptr_1,7,"hereadr"
- hereadr:
- rcall stackme_2
- .dw eHere
- ret ;with eg 010 on stack, the eeprom adr of eHere
- ;-----------------------------------------------------
- latestadr_1: ;classic latest. Puts adr of eLatest on stack. Currently 012 in eeprom
- header hereadr_1,9,"latestadr"
- latestadr:
- rcall stackme_2
- .dw eLatest
- ret ;with eg 012 on stack, the current eeprom adr of elatest
- ;----------------------------------
- varptradr_1: ; Puts adr of eVar on stack. Currently 014 in eeprom
- header latestadr_1,9,"varptradr"
- varptradr:
- rcall stackme_2
- .dw eVar
- ret ;with eg 014 on stack, the eeprom adr of eVar
- ;----------------------------------
- tx16_1: ;need easier word than "sendserialbyte"
- header varptradr_1,4,"tx16"
- tx16:
- rcall sendserialbyte
- ret
- ;--------------------------------------------
- space_1: ;send a space
- header tx16_1,5,"space"
- space:
- rcall stackme_2
- .dw $0020
- rcall emitcode
- ret ;with space sent
- ;------------------------------------------
- report_1: ;send a report at the start of the prog. Esp for system vars debugging
- header space_1,6,"report"
- report:
- ;.ifdef livetesting
- rcall gethere
- rcall dot
- rcall space
- rcall getlatest
- rcall dot
- rcall space
- rcall getvarptr
- rcall dot
- rcall space
- ;.endif
- ret
- ;----------------------------------------------------
- variable_1: ;classic variable
- header report_1,8,"variable"
- variable:
- rcall variablecode
- ;takemeout '~'
- ;rcall dumpbuf1
- ;rcall report
- ;takemeout '!'
- ret ;with variable's name and ram adr in word in flash dictionary
- ;---------------------------
- depth_1: ;classic size of stack
- header variable_1,5,"depth"
- depth:
- rcall depthcode
- ret ;with depth num on stack
- ;--------------------------------------
- rx18_1: ;wait for serial byte from terminal and put it into r18
- header depth_1,4,"rx18"
- rx18:
- rcall getserialbyte ;too long a name, hence this one
- ret ;with key typed in r18
- ;-------------------------------------
- ;LATEST:
- getkey_1: ;wait for key to be pressed and put ascii-16 on stack
- header rx18_1,6,"getkey"
- getkey:
- ldi r18,'-'
- clr r19
- mypush2 r18,r19
- rcall emitcode
- rcall rx18
- clr r19
- mypush2 r18,r19
- ret ;with key value on stack
- ;---------insert AVR Studio stuff here-----------------------------
- ;-------hhhhhhhhhhhhhhhhhhere -------------------------
- zerobranch_1: ;classic obranch code
- header getkey_1,7,"0BRANCH"
- zerobranch:
- ;( flag --) if flag is 0, do nothing,so as to go onto
- ; next instruction which will be a jump. If flag is 1 step over rjmp.
- mypopa
- or r16,r17 ;any 1's?
- breq out0b ;a 0 means get out
- ;if here the flag was 1 so we have to skip over next instruction
- pop r17
- pop r16
- clc
- inc r16
- ; inc r16 ;add one to ret adr. It's in WORDS
- brcc down0b
- inc r17
- down0b:
- push r16
- push r17
- out0b:
- ret
- ;--------------------------------------
- comp0branch_1: ;needed during IF compling
- header zerobranch_1,$0b,"comp0branch"
- comp0branch:
- ldi r16,low(zerobranch)
- ldi r17,high(zerobranch)
- mypush2 r16,r17 ;in words need to *2 to convert to bytes
- rcall two
- rcall star
- rcall compileme
- ret ;with "rcall 0branch"in next
- ;--------------------------
- if_1: ;classic if
- header comp0branch_1,$82,"if"
- if:
- rcall comp0branch
- rcall stkmyhere
- rcall stackme_2
- .dw 00000
- rcall comma
- ret ; with (rcall 0branch,0000) in dic and adr of the 0000 in myhere on stack
- ;-------------------------
- endif_1: ;classic "then" used in IF .. THEN, but endif better.
- header if_1,$85,"endif"
- endif: ;(there_adr -- rjmp code )
- rcall dup ;need there_adr twice,calc+ store
- rcall stkmyhere ;so we can use calc rjmp --> there - here -1
- rcall swapp ;because the jump is put into "there"
- rcall calcjumpcode ;(jmpcode now on stack)
- rcall swapp ;wrong way round for store !
- rcall store ;put jmpcode where there are just 0 placeholders near if
- ret ;with all the If..End if statement's codes in right place
- ;---------------------------------
- delay100ms_1: ;handy; delay for about 0.1 sec = 100 ms
- header endif_1,10,"delay100ms"
- delay100ms:
- .ifdef testing
- ldi r16,1
- .else
- ldi r16,60
- .endif
- upd100:
- rcall oneBitTime
- dec r16
- brne upd100
- ret ;after about a tenth of a second
- ;----------------------------------------------
- greq_1: ;(n m -- flag) flag =1 if n>=m, otherwise 0. Signed
- header delay100ms_1,2,">="
- greq:
- mypop2 r19,r18 ;that's m
- mypop2 r17,r16 ;that's n
- cp r16,r18
- cpc r17,r19 ;got this from the net
- brge downlo
- rcall zero ;if n<m
- rjmp outgr
- downlo:
- rcall one
- outgr:
- ret ;with flag on stack
- ;--------------------------------------
- lt_1: ;(n m -- flag) flag =1 if n<m, otherwise 0. Signed
- header greq_1,1,"<"
- lt:
- mypop2 r19,r18 ;that's m
- mypop2 r17,r16 ;that's n
- cp r16,r18
- cpc r17,r19 ;got this from the net
- brlt downlt
- rcall zero ;if n>=m
- rjmp outlt
- downlt:
- rcall one
- outlt:
- ret ;with flag on stack
- ;-------------------------------
- stkmyhere_1: ;( -- n16) useful
- header lt_1,9,"stkmyhere"
- stkmyhere1: ;Note spelling. put myhere on the stack, handy
- mypush2 myhere,r5
- ret
- ;------------------------------------------
- FBFlag_1: ;first variable. If 0 take input from serial, if 1 take it from BLOCK
- header stkmyhere_1,$46,"fbflag" ;NB first varaiable. Look at bit 6 of len
- FBFlag:
- rcall stackme_2
- .dw $01a0
- ret ;with first var adr 1a0 on stack
- ;-----------------------------------------
- FBPtr_1: ;second variable. points to current address in BLOCK. Starts at $1c0
- header FBFlag_1,$45,"fbptr" ;NB first varaiable. Look at bit 6 of len
- FBPtr:
- rcall stackme_2
- .dw $01a2
- ret ;with second var adr 1a2 on stack
- ;-------------------new---------
- k0_1: ;soon to be famous varaiable that counts T0 overflows
- header FBPtr_1,$42,"k0"
- k0:
- rcall stackme_2
- .dw $01a4
- ret ;with adr of k0 on the stack.
- ;============================================inserted k0=============
- readblock_1: ;set flag in ram $1a0,1 to 0001. Reads from BLOCK not serialfill
- header k0_1,9,"readblock"
- readblock:
- pushx ;macro, save xl, xh
- ldi xl,$a0
- ldi xh,$01 ;point to ram VARS, esp. FBFlag
- ldi r16,$01
- st x+,r16
- clr r16
- st x+,r16 ;that's FBFlag made 1.(ie use block fill not serialfill)
- popx ;restore x
- ret
- ;---------------------------------------------
- blockfinish_1: ;put at end of block to make next inputs via serialfill
- header readblock_1,11,"finishblock"
- blockfinish:
- ldi xl,$a0
- ldi xh,$01 ;point to ram VARS, esp. FBFlag
- clr r16
- st x+,r16
- st x+,r16 ;that's FBFlag made 0.(ie use serialfill not blockfill)
- ; rjmp cold ;reset everythig
- ;movw r16,zl
- ;rcall d1617
- rcall FBPtr
- rcall fetch
- mypopa
- rcall d1617
- rcall strout
- .dw $0b
- .db " blk finish"
- rjmp cold ;better? cold or quit?
- ;note, no ret as cold sorts out stacks for nice restart.
- ; TODO indicate when start is cold eg cold}} or cokd}} etc
- ;--------------------------------------------------
- ;major word. Assumes there's some colon defs in last 1k. ie at byte adr $1c00, $0e00 word adr.
- ;these defs end with the un-colon word "blockfinish". Each def ends in CR = $0d.
- ;Normally input comes into buf1 via serialfill. If flag in ram adr $01a0 is 0001 then we use blockfill
- ; but if the flag is 0000, default, we use serial fill. The adjacent am adr $01a2 is the pointer into
- ; the BLOCK. Initially at $1c00 but will change as the defs are brought in one by one. All come in
- ; one block and are compiled just like serial input (v, quickly typed) of lots of defs.
- blockfill_1: ;assumed called in quit when FGBFlag ($01a0) = 0001 and FBPtr ($01a2) = $1c00.
- header blockfinish_1,9,"blockfill"
- blockfill:
- rcall blockfillcode
- ret
- ;-------------------------------------------
- testingstopper_1: ;need a way of crashing to halt after BLOCK work when testing
- header blockfill_1,14,"testingstopper"
- testingstopper:
- rjmp testingstopper
- ;--------------------------------
- else_1: ;classic ELSE. Won't compile nicely thru block as keeps going immediate
- header testingstopper_1,$84,"else"
- else: ;(n16 --) expects if's adr on stack
- ;try this order above and below here
- ; rcall endif ;see endif
- rcall dup ;need there_adr twice,calc+ store
- rcall stkmyhere ;so we can use calc rjmp --> there - here -1
- rcall two
- rcall plus ;because we have to jump over the 0000 adr to be filled in later
- rcall swapp ;because the jump is put into "there"
- rcall calcjumpcode ;(jmpcode now on stack)
- rcall swapp ;wrong way round for store !
- rcall store ;put jmpcode where there are just 0 placeholders near if
- ;ret ;with all the If..End if statement's codes in right place
- rcall stkmyhere ;for endif at the end of def using else
- rcall zero ;filled in by endif
- rcall comma
- ret
- ;--------------------------------------------------------------
- rs_1: ;( adr16 len16 -- ) ram string-print (assembler doesn't like rs._1 etc)
- header else_1,3,"rs."
- rs:
- pushx
- mypopb ;the len's now in r18,19
- mypop2 xh,xl ;str adr in x
- uprs:
- ld r16,x+ ;get char from string
- rcall tx16 ; and print it to term
- dec r18 ;len--, finished?
- brne uprs
- popx ;recover x for other work
- ret ;with ram string printed to term
- ;-------------------------------------------
- qmark_1: ;prints ?
- header rs_1,5,"qmark"
- qmark:
- ldi r16,'?'
- rcall tx16
- ret ;with ? printed to terminal
- ;-----------------------------------------------
- ;LATEST:
- findfirstvar_1: ;(--adr16) search dic for topmost var. Return with its RAM adr.
- header qmark_1,12,"findfirstvar"
- findfirstvar:
- rcall findfirstvarcode
- ret ; with RAM adr of first var on stack. Useful after forget.
- ;)))))))))))))))))))))))))))))
- ;LATEST:
- compstrout_1: ;needed infront of every number compiled
- header findfirstvar_1,10,"compstrout"
- compstrout:
- ldi r16,low(strout)
- ldi r17,high(strout)
- mypush2 r16,r17 ;in words need to *2 to convert to bytes
- rcall two
- rcall star
- rcall compileme
- ret
- ;000000000000000000000000
- squote_1: ; classic S" . Used to output strings in compiled words.
- header compstrout_1,$82,"S'" ;compiler doesn't like S" in quotes
- squote:
- rcall compstrout
- rcall stkmyhere ;stack adr of 00 that length is going into
- rcall zero
- rcall comma
- pushz ;going to use z to point to RAM dic
- ;inc xl
- ;brcc downsq ;step over space after
- movw zl,r4 ;z <-- myhere
- clr r18 ;counter
- movtxt:
- ld r16,x+ ;first char to move is space after S'
- cpi r16,$27 ;got to end of string? ;$27 = '
- breq outsq ;keep filling in chars in dic til hit a '
- st z+,r16 ;fill up ram dic with string after S'
- inc r18 ;this is for len. later on
- rjmp movtxt
- nop
- ; may have an odd num of chars. If so add padding byte.
- outsq:
- sbrs r18,0 ;is r18 an odd num eg. len = 5
- rjmp downsq
- ;if here lsb = 1 in len so we're on a padding byte and have to add 1 to get to a 2 byte boundary
- clr r16
- st z+,r16 ;insert padding byte
- downsq:
- clr r19 ;topup
- mypush2 r18,r19 ;now len is on the mystack (so have ( adrOf00 len--)
- rcall swapp
- rcall store ; mystk empty and len word in right place just before the str.
- movw myhere, zl ;advance myhere so that next word compiles straight after
- popz
- ret
- ;0000000000000000000000000000000000000000000
- while_1: ; (--adr16) classic in begin..while..repeat.
- header squote_1,$85,"while"
- while:
- rcall comp0branch ;if true skip over next jump
- rcall stkmyhere ;not pos of 00 for leter fill in by repeat
- ;get order above and below this right
- rcall zero ;temp filler for branch if false
- rcall comma ;compile this 00. repeat will fill it in later
- ret ;with adr of unfilled branch on my stack and 0branch compiled.
- ;--------------------------------------------
- repeat_1: ;( adrb adrw --) classic. adrb,adrw are stacked by begin,while resp. Myheres
- header while_1,$86,"repeat"
- repeat:
- ; rcall endif ; this will fill in the 00 done by while with jmp to past repeat
- ;got this from else_
- rcall dup ;need there_adr twice,calc+ store
- rcall stkmyhere ;so we can use calc rjmp --> there - here -1
- rcall two
- rcall plus ;because we have to jump over the rjmp to begin we create below
- rcall swapp ;because the jump is put into "there"
- rcall calcjumpcode ;(jmpcode now on stack)
- rcall swapp ;wrong way round for store !
- rcall store ;put jmpcode where there are just 0 placeholders near if
- rcall again ; this will give a rjmp, uncondit back to begin.
- ret ;with all the begin..while..repeat all filled in.
- ;-----------------------------------
- until_1: ;( adr16 --) enter with adr of begin on stack. Loop back to there if true.
- header repeat_1,$85,"until"
- until:
- rcall comp0branch
- rcall again ;again code gets us back to start, after begin
- ret ;with two jmps (obranch and again jump ) all in right places
- ;------------------------------------
- ;: updateevar findfirstvar varptradr e! ; $0d
- updateevar_1: ;housekeeping. Read top var on cold start to make sure pointer ready for nxt var
- header until_1,10, "updateevar"
- updateevar:
- rcall findfirstvar
- rcall two
- rcall plus ;so that next var takes next empty slot
- rcall varptradr ;now have eg 01a4 0014 on stack
- rcall estore
- ret ;with eeprom ptr updated to value of current top var
- ;99999999999999999999999999999999999999999
- for_1: ;( -- adr) unclassic for part of for-next loop. Same as begin
- header updateevar_1,$83,"for"
- for:
- rcall stackmyhere ;put next adr on stack. For next to pick up later.
- ret ;with adr on stack
- ;-----------------------------------------
- next_1: ;(adr --). Part of for..next. Assumes for has put its adr on stk
- header for_1,$84,"next"
- next:
- rcall compnextcode ;insert code to dec avr and leave flag for 0branch
- rcall comp0branch
- rcall again ;to provide jump (usually taken but not when var =0)
- ret ;with next all set up to test flag and loop back to for if (var) <= 0
- ;------------------------------------------
- forg_1:
- header next_1, 6, "forget"
- forg:
- rcall forg1
- rjmp cold
- ret ;never used
- ;---------------------------------------
- constant_1: ;( n16 --) classic constant word
- header forg_1,8,"constant"
- constant:
- rcall constantcode
- ret ;with new constant in dictionary
- ;---------------------------------------
- mask_1: ;( n16 -- n16) eg 3 mask produces 0008, ie bit 3 set, on the stack
- header constant_1,4,"mask"
- mask:
- rcall maskcode
- ret ; with mask byte on stack (lower byte)
- ;-------------------------
- setbit_1: ;(n1 n2 --) eg 0003 0038 setbit will make bit 3 in PORTNB a 1
- header mask_1,6,"setbit"
- setbit:
- rcall setbitcode
- ret ;with bit set in RAM byte, mostlu used with IO like PORTB
- ;----------------------------------
- clrbit_1: ;(n1 n2 --) eg 0003 0038 clrbit will make bit 3 in PORTNB a 0
- ;header setbit_1,6,"clrbit"
- header setbit_1,6,"clrbit"
- clrbit:
- ;rcall setbitcode ;takeout, testing.
- rcall clrbitcode ;temmp redirection to sort out innaction with eg 0003 0032 clrbit
- ;rcall clrbitcode
- ;rjmp test1 ;testing, take out later
- ret ;with bit cleared in RAM byte, mostlu used with IO like PORTB
- ;----------------------------------------
- bitfetch_1: ;(n1 n2 -- flag) n1 = bitnum, n2 = adr of RAM/IO. Flag reports bit is 1/0
- header clrbit_1,4,"bit@"
- bitfetch:
- rcall bitfetchcode
- ret ;with 1 if bit set or 0 if bit cleared.
- ;----------------------
- gt_1: ;(n1 n2 -- flag) true if n1>n2 Signed.
- header bitfetch_1,1,">"
- gt:
- rcall swapp
- rcall lt
- ret ;with flag on stack
- ;----------------------------
- leq_1: ;(n1 n2 -- flag) flag =1 if n1 <= n2. Signed
- header gt_1,2,"<="
- leq:
- rcall swapp
- rcall greq
- ret ;with flag=1 if n1<=n2, 0 otherwise
- ;---------------------------------
- wds_1: ;(--) show just top five words. Best for testing.
- header leq_1,3,"wds"
- wds:
- rcall wdscode
- ret ; with just 5 words printed
- ;----------------------------------
- semireti_1: ;like ret but goes into ISRs and ends with reti = $9518
- header wds_1,$85,";reti"
- semireti:
- nop
- rcall insertreti ;compile reti
- ;not sure about following delays. Overkill but leave at this stage as they work.
- ;rcall oneBitTime
- rcall delay100ms ;trying some waits to give spm time
- rcall burnbuf2and3
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- ;rcall oneBitTime ;ditto
- ;rcall oneBitTime ;ditto. Seems to be working. eeprom writes wreck spm's.
- rcall rbrac ;after semi w'got back to executing
- ; rcall updatevars ;update HERE and LATEST in eeprom
- rcall updatevars2 ;Better version. update HERE and LATEST in eeprom
- ret
- ;---------------------------------------
- not_1: ;(flag16--~flag16) change 1 to 0 and vice versa on mystack
- header semireti_1,3,"not"
- not:
- mypopa ;r16,17 <--flag
- or r16,r17
- breq gotazero
- gotn1:
- clr r16
- clr r17 ;there were some 1's in r16,17 so make a zero
- rjmp outnot
- gotazero:
- inc r16 ;see above. r16,17 were both 0
- outnot:
- mypush2 r16,r17
- ret ;with flag, swapped in logic, on stack
- ;--------------------------------
- ;: cn constant ; : d. depth . ; : v variable ; all need dic entry. Handy.
- cn_1: ;(--) handy. Instead of writing "constant"
- header not_1,2,"cn"
- cn:
- rcall constant
- ret
- ;-----------------------------------------
- v_1: ;(--) handy. Like cn above but better than writing "variable". Quicker
- header cn_1,1,"v"
- v:
- rcall variable
- ret
- ;-----------------------------------------
- ddot_1: ;quick print of mystack depth. Handy
- header v_1,2,"d."
- ddot:
- rcall depth
- rcall dot ;print the depth
- ret
- ;----------------------------------.db ": 1= 0= not ; $0d
- oneeq_1: ; (flag--flag), test to see if tos is a 1
- header ddot_1,2,"1="
- oneeq:
- rcall zeroequal
- rcall not
- ret ;with new flag on stack
- ;----------------------------------------
- globIntX_1: ;having hard time turning global Int off using 0007 005f clrbit
- header oneeq_1,8,"globIntX"
- globIntX:
- cli
- ret
- ;--------------------------------
- globInt_1: ;
- header globIntX_1,7,"globInt"
- globInt:
- sei
- ret
- ;-------------------------------
- qfetchdot_1: ;? does job of both @ and . (handy)
- header globInt_1,1,"?"
- qfetchdot:
- rcall fetch
- rcall dot
- ret
- ;------------------------------
- stopT0_1:
- header qfetchdot_1,6,"stopT0"
- stopT0:
- clr r16
- sts $0053, r16 ; stops t0 counter. NB don't use TCCR0B = $0033 with sts
- ret
- ;------------------------------
- ;NB there's another version, startT03, that divides by 64.
- startT0_1:
- header stopT0_1,7,"startT0"
- startT0:
- ldi r16,1 ;fastest speed for t0 counter, once every cycle it ticks over
- sts $0053, r16 ; starts t0 counter.
- ret
- ;----------------------------------
- dmp2_1: ;handy = dumpbuf1
- header startT0_1,4,"dmp2"
- dmp2:
- rcall dumpbuf2
- ret
- ;----------------------
- dumpVarSpace_1:
- header dmp2_1,12,"dumpVarSpace"
- dumpVarSpace:
- rcall dumpVarSpaceCode
- ret
- ;--------------------
- t0fetch_1: ;( -- n) fetch TCNT0 using lds. C@ not working for me
- header dumpVarSpace_1,3,"t0@"
- t0fetch:
- rcall TCNT0Fetch ;(--n)
- ret ; with val in TCNT0 on stack
- ;-------------------------------------
- t0store_1: ;( n--). Store val on stack into TCNT0. Only lsbye.
- header t0fetch_1,3,"t0!"
- t0store:
- rcall TCNT0Store
- ret ; with new value from stack pushed into TCNT0. This had better work. Taking lot of time with c@
- ;------------------------------
- delay1bit_1: ;at 600 baud
- header t0store_1,9,"delay1bit"
- delay1bit:
- rcall oneBitTime
- ret
- ;----------------------------
- halfbt_1: ;half bit time at 600 baud. ie 1/1200 sec
- header delay1bit_1,6,"halfbt"
- halfbt:
- rcall halfBitTime
- ret ;just experimenting. Could lose this later.
- ;-----------------------
- ;this took 106 ticks at 8Mhz/64/1200. Expected 104 which works for rjmp to fastHalf. Why?
- fastHalfA_1: ;run m/c fastHalf routine that times halfBitTime in various ways.
- header halfbt_1,9,"fastHalfA"
- fastHalfA:
- rcall fastHalf
- ret
- ;----------------------
- clrTCNT02_1: ;standard resetting of TCNT0, handy during testing
- header fastHalfA_1, 8, "clrTCNT0"
- clrTCNT02: ;NB there's another clrTCNT0
- rcall clrTCNT0
- ret
- ;-------------------------
- fastHalfB_1: ;add a bit of forth to fastHalfA to see how it affects times
- header clrTCNT02_1,9,"fastHalfB"
- fastHalfB:
- ; rcall StopT0
- ; rcall clrTCNT0
- rcall BfastHalf
- ret ;use like this : clrTCNT0 fastHalfB and check time.Expect same as fastHalfA
- ;----------------------------
- startT03_1: ;start TCNT0 with prescale 3 = div by 64. Handy.
- header fastHalfB_1,8,"startT03"
- startT03:
- LDI r16,0b0000_0011 ; 2=/8 3=/64 4 = /256 5 /1024 SET TIMER PRESCALER TO , 03 is /64
- OUT TCCR0B,r16 ;now timer 0 started
- ret
- ;-----------------------
- LATEST:
- klrbit_1: ;take out testing problems with clrbit
- header startT03_1,6,"klrbit"
- klrbit:
- ;rcall test1
- ;rcall clrbitcode
- rcall clrbit
- ret
- ;-----------------------------------------------
- HERE:
- .db "444444444444444444444444444444"
- ;---------------stackme_2 used to live here---------------------------------
- ;====================================================================================================
- .ORG 0
- Lreset: ;adr 0
- rjmp cold
- Lint0: ;adr 1
- rjmp cold
- Lpcint0: ;adr 2
- rjmp PC_change_ISR ;also can rjmp pcISR . Which is in takeOuts file
- TIMER1_COMPA: ;adr 3
- rjmp cold
- TIMER1_OVF: ;adr 4
- rjmp cold
- TIMER0_OVF: ;adr 5
- rjmp TOVO_ISR_k0 ;TOVO_ISR_1d0 ; ;TOVO_ISR ; ; ;rjmp testT0_ISR0
- EE_RDY: ;adr 6
- rjmp cold
- ;.db " : beee begin 0002 while 0003 repeat 0004 ; ",$0d
- ;.db ": myworxxd 0001 if 0005 dup endif ; ", $0d
- ;-----------------------------------------------------
- .ORG $000f
- typein: .db "readblock ",$0d
- cold: ;come here on reset or for big cleanup
- ldi r16, low(RAMEND)
- out SPL, r16
- ldi r16,high(RAMEND)
- out SPH, r16
- ldi YL,low(myStackStart)
- ldi YH,high(myStackStart)
- rcall housekeeping
- ;rcall test_buf2ToFlashBuffer
- ;rjmp cold
- ;rcall blockfillcode
- ;rcall interpretLine
- ;rcall blockfillcode
- ;rcall blockfillcode
- ;rcall blockfinish
- ;rcall test_rs
- ;rcall showCounters
- ;rjmp blinkTimer
- ;rcall test_strout
- ;rjmp interrupt_0
- ;rjmp startT0_0
- ;rjmp quickT0
- ;rjmp testio ;worked
- ;rjmp test_usiRxT
- ;rjmp serialTest0
- ;rjmp serialTest1
- ;rjmp serialTest3
- ;rjmp serialTest4
- ;rjmp test_dhighR
- ;rjmp fetchTest
- ;rjmp test_dumpbuf1
- ;rjmp test_serialStrOut
- ;rcall dumpbuf2
- ;rcall dumpVarSpace
- ;rjmp test_tfs
- ;rjmp fastHalf
- ;rjmp pollPB3
- ;here3: rjmp here3
- quit:
- ldi r16, low(RAMEND)
- out SPL, r16
- ldi r16,high(RAMEND)
- out SPH, r16
- ; ldi YL,low(myStackStart)
- ; ldi YH,high(myStackStart)
- ;---------new------------
- rcall FBFlag ;put $1a0 (blockfill flag) on stack
- rcall fetch ;either 0000 (do serialfill) or 0001 (blockfill)
- mypopa ;r16,17 get flag
- tst r16 ;is flag (lower byte anyway) a zero?
- .ifndef testing
- breq doSF ;flag = 0 do (normal) serialfill
- .else
- breq getli
- .endif
- rcall blockfillcode ;because (if here) flag is a 1 = do
- ;rjmp interp ;interpret the block fill def
- rcall interpretLine ;but only if filling from BLOCK
- rjmp quit ;quit
- .ifdef testing
- getli:
- rcall getline0
- rcall interpretLine
- quithere:
- rjmp quit;here
- .endif
- .ifndef testing
- doSF:
- rcall serialFill
- interp: ;have buf1 filled with words, def etc now find them on dic etc.
- clr STOP
- clr r1
- clr SECONDLETTER
- clr BOTTOM
- rcall interpretLine
- rjmp quit
- .endif
- ;-------------------------------------------------------------
- ;mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
- ;--------------------------------------------------------------
- getline0: ;force a line into buf1 via flash string. Simulates GETLINE
- ldi zl, low(typein<<1)
- ldi zh, high(typein<<1)
- ldi xl, low(buf1)
- ldi xh, high(buf1)
- type0:
- lpm r16,Z+
- st x+,r16
- cpi r16,0x0d ;have we got to the end of the line?
- brne type0
- ret
- ;--------------------------------------------
- serialFill: ;main input routine from terminal. Output OK} then
- ; wait until buf1 has string of words ( <64 chars?) ending in $0d
- rcall clrbuf1
- rcall CR
- ;rcall report
- rcall OK
- rcall rxStrEndCR
- ret ; buf1 now filled with words from terminal
- ;--------------------------------------------------------------
- interpretLine: ;given line of words in buf one, search for words one by one. Don't do code
- ; or compile at this stage, just find and report that and go into next one.
- rcall pasteEOL
- ldi xl, low(buf1)
- ldi xh,high(buf1) ;last 3 statemnts are done onece. Now the main loop.
- clr FOUNDCOUNTER ;counts finds in line parsing.
- nextWord:
- tst STOP
- brne stopLine
- nop
- rcall word
- rcall findWord
- rcall dealWithWord ;go and run code STATE=0, or compile (STATE =1).{ c0de, comp1le}
- rjmp nextWord
- stopLine:
- ret
- ;----------------------------------------------------------
- ;WORD gets x to point to start of word (copy in w=r24,25) with the length in len = r20
- ;assume word points to somewhere in buf1. Should advance thru spaces=0x20 to first real char
- word: ;maybe give it a header later
- ld SECONDLETTER, x ;for debugging. TODO. Should be firstletter?
- ld r16,x+ ;get char
- cpi r16,0x20 ;is it a space?
- breq word ;if so get next char
- ;if here we're point to word start. so save this adr in w
- mov r24,xl
- mov r25,xh ;wordstart now saved in w
- clr r20 ;length initially 0
- nextchar:
- inc r20 ;r20 = word length
- ld r16,x+ ;get next char
- cpi r16,0x20
- brne nextchar
- dec r24 ;adjust start of word
- ;if here we've found a word.Starting at w length in r20.x points to space just past word
- ret
- ;----------------------------------------
- compare: ;given a word in buf1 and a word in the dic are they the same? The word in the dic is pointed to by Z.
- ; and the word in buf1 is pointed to by w=r24,25. len = r20. Z on entry points to the link. Needs +2 to
- lpm r23,z+
- lpm r22,z+ ;store next link in v=r22,23. z now points to len byte
- startc:
- ;TODO save copy of flash word in r21 and also do masking of immediates
- push r20 ;save length
- lpm r16,Z+ ;length of dictionary word, first entry now in r16
- mov r21,r16 ;copy length-in-flash to r21. May have immediate bit (bit 7)
- andi r16,$0f ;mask off top nibble before comparing
- cp r16,r20 ;same lengths?
- brne outcom ;not = so bail out
- ;if here the words are the same length, what about the rest of the chars.First get x to point to word.
- mov xl,r24
- mov xh,r25 ;x now point to start of buf1 word
- upcom:
- lpm r16,z+
- ld r17,x+ ;get one corresponding char from each word
- cp r16,r17 ;same word?
- brne outcom ;bail out if chars are different
- dec r20 ;count chars
- brne upcom ;still matching and not finished so keep going
- ;if here r20 is 0 so match must have been perfect so FOUND = 1
- clr FOUND
- inc FOUND
- outcom:
- pop r20 ;get old lngth of buf1 word back
- ret
- ;-------------------------------------------
- jmpNextWord: ;go to next word in the dictionary. Assume v=r22,23 contains next link word(not byte)
- ; and w = r24,25 contains RAM word start with len in r20
- ;exit with z pointing to next word ready for next COMPARE.
- clc
- rol r22
- rol r23 ;above 3 instructions change word address into byte address by doubling
- movw r30,r22 ;z now points to next word
- ret
- ;-----------------------------------------
- doLatest: ;set up so first jump in dictionary is to top=LATEST and other flags set up.
- ; ldi vl, low(LATEST)
- ; ldi vh, high(LATEST)
- nop
- rcall getlatest ;from eeprom. Now on stack
- mypop2 vh,vl ;
- ; rcall halve
- clr FOUND
- clr BOTTOM ;not yet found the match, not yet at the bottom. Either will stop search.
- clr STOP ;keep parsing words til this goes to a 1
- ret
- ;---------------------------------------------
- ;-----------------------------------------------------------------
- findWord:
- rcall doLatest
- nop
- ;rcall dumpbuf1
- ;FIND reg values here.
- rcall considercode
- upjmpf:
- rcall jmpNextWord
- takemeout 'f'
- rcall compare
- tst FOUND
- brne stopsearchf ;if last compare got a match (FOUND=1) then stop searching
- tst vl
- brne upjmpf ;if v=0000 then we've hit the bottom of the dictionary
- tst vh
- brne upjmpf ;not found and not at bottom so keep going
- ;if here FOUND =0, ie no match yet and we've hit the bottom of the dictionary
- clr BOTTOM
- inc BOTTOM ;exit with FOUND=0 and BOTTOM =1
- stopsearchf:
- nop
- ret
- ;----------------------------
- test_interpretLine:
- rcall interpretLine
- til: rjmp til ;** with r24 pointing to 'S' and FOUND = r15 =1
- ;------------------------------
- dealWithWord: ;come here when it's time to compile or run code
- ;Good debugging spot. Enter here with Z pointing to CFA of word found. Y points to myStack. X points to just
- ; past the word we are seeking (w-s). r10 is 2nd letter of w-s. w = start adr of w-s. v is a link
- ; to the next word in dic. Either just below the found word or 0000 if we get to the bottome with no match
- ;
- nop
- tst FOUND
- breq notfound
- inc FOUNDCOUNTER
- ;want to hop over filler bytes,0's added to keep codes on even byte boundaries
- ; so if r30 is odd at this stage inc it. odd is lsbit = 1.
- sbrs r30,0 ;skip next instruction if final bit lsb = 1
- rjmp downd
- ;if here lsb = 1 so we're on a padding byte and have to add 1 to get to a 2 byte boundary
- inc r30
- ;brcc downd CHANGE. !! to brne, mistake that casued occasional deep problems.
- ;1:13 p.m. Thursday, 11 December 2014
- brne downd
- inc r31 ;add one to z before converting to bytes
- ;have to ask at this point, is the word immediate? If so, bit 7 of r21 will be set.
- downd:
- sbrs r21,7
- rjmp downdw ;not immediate so just go on with STATE test
- rjmp executeme ;yes, immediate so execute every time.
- downdw: tst STATE
- breq executeme
- rcall compilecode
- rjmp outdww
- executeme:
- clc
- ror zh
- ror zl ;put z back into word values
- rcall executeCode
- .MESSAGE "Word found"
- rjmp outdww
- notfound:
- nop
- ; .MESSAGE "Word not found"
- ; clr STOP
- ; inc STOP ;stop parsing line
- takemeout 'n'
- rcall numberh ; word not in dict so must be a number? Form = HHHH
- ;now have to add 3 to x so it points past this word ready not next one
- clc
- inc r26
- inc r26
- inc r26
- brcc outdww
- inc r27 ;but only if overflow
- nop
- outdww:
- ret ;with STOP =1 in not a number
- ;------------------------------------------------------------------------
- pasteEOL: ;when a line of text is TYPEd into buf1 it should end with CR=$0d. This gets replaced with ]}, a
- ; special end of line word. When the word is invoked it casues a QUIT back to the waiting for input stage.
- ; Start at buf1 start and inspect each char for a $0D. When found replace with a "$20 S $20 "
- ldi xl, low(buf1)
- ldi xh, high(buf1) ;pnt to start of buffer
- clr r17
- nxtChar:
- inc r17 ;r17 is counter. Bail out when r17 > BUF1LENGTH
- cpi r17, BUF1LENGTH -3
- breq outProb
- ld r16, x+
- cpi r16, $0d
- brne nxtChar
- ;if here we've found a $0d in buf1 before the end, so replace with an EOL token. x points to just after it.
- ldi r16,$20
- st -x, r16 ;back up. Then go forward.
- TAKEMEOUT 'p'
- ; ldi r16, ']'
- ldi r16,$20 ;This took about 4 day's work to insert this line. Why is it needed?
- st x+, r16
- ldi r16,'S'
- st x+, r16
- ; ldi r16, '}'
- ; st x+, r16
- ldi r16, $20
- st x, r16
- rjmp outpel
- outProb:
- takemeout 'O'
- nop
- .MESSAGE "Couldn't find $0d"
- outpel:
- ret
- ;-------------------------------------
- executeCode: ;with Z pointing to cfa. Not sure whether to jmp or call
- ijmp
- ret
- ;---------------------------------------
- test_fetch: ;do run thru of @
- rcall getline0 ;change later to real getline via terminal
- rcall pasteEOL
- ldi xl, low(buf1)
- ldi xh,high(buf1) ;last 3 statemnts are done onece. Now the main loop.
- ldi r16,$62
- mypush r16
- ldi r16,$0
- mypush r16 ;should now have adr $0062 on mystack
- rcall fetch
- tf1:
- rjmp tf1
- ;---------------------------------
- test_cfetch: ;do run thru of @
- rcall getline0 ;change later to real getline via terminal
- rcall pasteEOL
- ldi xl, low(buf1)
- ldi xh,high(buf1) ;last 3 statemnts are done onece. Now the main loop.
- ldi r16,$62
- mypush r16
- ldi r16,$0
- mypush r16 ;should now have adr $62 on mystack
- rcall cfetch
- tcf1:
- rjmp tcf1
- ;----------------------------
- test_store:
- rcall getline0 ;change later to real getline via terminal
- rcall pasteEOL
- ldi xl, low(buf1)
- ldi xh,high(buf1) ;last 3 statemnts are done onece. Now the main loop.
- ldi r16,$62
- ldi r17,$0
- mypush2 r16,r17 ;should now have adr $62 on mystack
- ldi r16, $AB
- ldi r17, $CD
- mypush2 r16,r17 ;now have $ABCD on mystack
- rcall store
- ts1:
- rjmp ts1
- ;------------------------
- test_cstore:
- rcall getline0 ;change later to real getline via terminal
- rcall pasteEOL
- ldi xl, low(buf1)
- ldi xh,high(buf1) ;last 3 statemnts are done onece. Now the main loop.
- ldi r16,$62
- ldi r17,$0
- mypush2 r16,r17 ;should now have adr $62 on mystack
- ldi r16, $AB
- ; ldi r17, $CD
- mypush r16 ;now have $ABCD on mystack
- rcall cstore
- ts11:
- rjmp ts11
- ;Now put arith routines here. Are from AVR200. Just using 16*16 for * but get 32bit result.
- ;***************************************************************************
- ;*
- ;* "mpy16s" - 16x16 Bit Signed Multiplication
- ;*
- ;* This subroutine multiplies signed the two 16-bit register variables
- ;* mp16sH:mp16sL and mc16sH:mc16sL.
- ;* The result is placed in m16s3:m16s2:m16s1:m16s0.
- ;* The routine is an implementation of Booth's algorithm. If all 32 bits
- ;* in the result are needed, avoid calling the routine with
- ;* -32768 ($8000) as multiplicand
- ;*
- ;* Number of words :16 + return
- ;* Number of cycles :210/226 (Min/Max) + return
- ;* Low registers used :None
- ;* High registers used :7 (mp16sL,mp16sH,mc16sL/m16s0,mc16sH/m16s1,
- ;* m16s2,m16s3,mcnt16s)
- ;*
- ;***************************************************************************
- ;***** Subroutine Register Variables
- .def mc16sL =r16 ;multiplicand low byte
- .def mc16sH =r17 ;multiplicand high byte
- .def mp16sL =r18 ;multiplier low byte
- .def mp16sH =r19 ;multiplier high byte
- .def m16s0 =r18 ;result byte 0 (LSB)
- .def m16s1 =r19 ;result byte 1
- .def m16s2 =r20 ;result byte 2
- .def m16s3 =r21 ;result byte 3 (MSB)
- .def mcnt16s =r22 ;loop counter
- ;***** Code
- mpy16s: clr m16s3 ;clear result byte 3
- sub m16s2,m16s2 ;clear result byte 2 and carry
- ldi mcnt16s,16 ;init loop counter
- m16s_1: brcc m16s_2 ;if carry (previous bit) set
- add m16s2,mc16sL ; add multiplicand Low to result byte 2
- adc m16s3,mc16sH ; add multiplicand High to result byte 3
- m16s_2: sbrc mp16sL,0 ;if current bit set
- sub m16s2,mc16sL ; sub multiplicand Low from result byte 2
- sbrc mp16sL,0 ;if current bit set
- sbc m16s3,mc16sH ; sub multiplicand High from result byte 3
- asr m16s3 ;shift right result and multiplier
- ror m16s2
- ror m16s1
- ror m16s0
- dec mcnt16s ;decrement counter
- brne m16s_1 ;if not done, loop more
- ret
- ;----------------------------------------------------------
- ;***** Multiply Two Signed 16-Bit Numbers (-12345*(-4321))
- test_mpy16s:
- ldi mc16sL,low(-12345)
- ldi mc16sH,high(-12345)
- ldi mp16sL,low(-4321)
- ldi mp16sH,high(-4321)
- rcall mpy16s ;result: m16s3:m16s2:m16s1:m16s0
- ;=$032df219 (53,342,745)
- tmpy: rjmp tmpy
- test_mpy16s0:
- ldi mc16sL,low(123)
- ldi mc16sH,high(123)
- ldi mp16sL,low(147)
- ldi mp16sH,high(147)
- rcall mpy16s ;result: m16s3:m16s2:m16s1:m16s0
- tmpy0: rjmp tmpy0
- ;-----------------------
- test_star:
- ldi r16,-$7b
- mypush r16
- ldi r16,$00
- mypush r16 ;that's decimal 123 on stack
- ldi r16,$93
- mypush r16
- ldi r16,$00
- mypush r16 ; and thats dec'147
- rcall star
- tsr: rjmp tsr
- ;--------------------------
- ;***************************************************************************
- ;*
- ;* "div16s" - 16/16 Bit Signed Division
- ;*
- ;* This subroutine divides signed the two 16 bit numbers
- ;* "dd16sH:dd16sL" (dividend) and "dv16sH:dv16sL" (divisor).
- ;* The result is placed in "dres16sH:dres16sL" and the remainder in
- ;* "drem16sH:drem16sL".
- ;*
- ;* Number of words :39
- ;* Number of cycles :247/263 (Min/Max)
- ;* Low registers used :3 (d16s,drem16sL,drem16sH)
- ;* High registers used :7 (dres16sL/dd16sL,dres16sH/dd16sH,dv16sL,dv16sH,
- ;* dcnt16sH)
- ;*
- ;***************************************************************************
- ;***** Subroutine Register Variables
- .def d16s =r13 ;sign register
- .def drem16sL=r14 ;remainder low byte
- .def drem16sH=r15 ;remainder high byte
- .def dres16sL=r16 ;result low byte
- .def dres16sH=r17 ;result high byte
- .def dd16sL =r16 ;dividend low byte
- .def dd16sH =r17 ;dividend high byte
- .def dv16sL =r18 ;divisor low byte
- .def dv16sH =r19 ;divisor high byte
- .def dcnt16s =r20 ;loop counter
- ;***** Code
- div16s: ;push r13 ;PB !!
- ;push r14 ;PB !!
- mov d16s,dd16sH ;move dividend High to sign register
- eor d16s,dv16sH ;xor divisor High with sign register
- sbrs dd16sH,7 ;if MSB in dividend set
- rjmp d16s_1
- com dd16sH ; change sign of dividend
- com dd16sL
- subi dd16sL,low(-1)
- sbci dd16sL,high(-1)
- d16s_1: sbrs dv16sH,7 ;if MSB in divisor set
- rjmp d16s_2
- com dv16sH ; change sign of divisor
- com dv16sL
- subi dv16sL,low(-1)
- sbci dv16sL,high(-1)
- d16s_2: clr drem16sL ;clear remainder Low byte
- sub drem16sH,drem16sH;clear remainder High byte and carry
- ldi dcnt16s,17 ;init loop counter
- d16s_3: rol dd16sL ;shift left dividend
- rol dd16sH
- dec dcnt16s ;decrement counter
- brne d16s_5 ;if done
- sbrs d16s,7 ; if MSB in sign register set
- rjmp d16s_4
- com dres16sH ; change sign of result
- com dres16sL
- subi dres16sL,low(-1)
- sbci dres16sH,high(-1)
- d16s_4: ;pop r14 ;PB!!
- ;pop r13 ;PB!!
- ret ; return
- d16s_5: rol drem16sL ;shift dividend into remainder
- rol drem16sH
- sub drem16sL,dv16sL ;remainder = remainder - divisor
- sbc drem16sH,dv16sH ;
- brcc d16s_6 ;if result negative
- add drem16sL,dv16sL ; restore remainder
- adc drem16sH,dv16sH
- clc ; clear carry to be shifted into result
- rjmp d16s_3 ;else
- d16s_6: sec ; set carry to be shifted into result
- rjmp d16s_3
- ;-----------------------------------------------
- test_div16s:
- ;***** Divide Two Signed 16-Bit Numbers (-22,222/10)
- ldi dd16sL,low(-22222)
- ldi dd16sH,high(-22222)
- ldi dv16sL,low(10)
- ldi dv16sH,high(10)
- rcall div16s ;result: $f752 (-2222)
- ;remainder: $0002 (2)
- forever:rjmp forever
- ;----------------------------------
- test_slashMod:
- ldi r16,$12
- mypush r16
- ldi r16,$34
- mypush r16
- ldi r16,$56 ;NB this is $3412 not $1234
- mypush r16
- ldi r16,$00
- mypush r16
- rcall slashMod ;$3412 / $56 = $9b rem 0 works
- tslm: rjmp tslm
- ;---------------------------------------
- ;From http://www.avr-asm-tutorial.net/avr_en/calc/CONVERT.html#hex2bin
- ; Hex4ToBin2
- ; converts a 4-digit-hex-ascii to a 16-bit-binary
- ; In: Z points to first digit of a Hex-ASCII-coded number
- ; Out: T-flag has general result:
- ; T=0: rBin1H:L has the 16-bit-binary result, Z points
- ; to the first digit of the Hex-ASCII number
- ; T=1: illegal character encountered, Z points to the
- ; first non-hex-ASCII character
- ; Used registers: rBin1H:L (result), R0 (restored after
- ; use), rmp
- ; Called subroutines: Hex2ToBin1, Hex1ToBin1
- .def rBin1H =r17
- .def rBin1L = r16
- .def rmp = r18
- ;
- Hex4ToBin2:
- clt ; Clear error flag
- rcall Hex2ToBin1 ; convert two digits hex to Byte
- brts Hex4ToBin2a ; Error, go back
- mov rBin1H,rmp ; Byte to result MSB
- rcall Hex2ToBin1 ; next two chars
- brts Hex4ToBin2a ; Error, go back
- mov rBin1L,rmp ; Byte to result LSB
- sbiw ZL,4 ; result ok, go back to start
- Hex4ToBin2a:
- ret
- ;
- ; Hex2ToBin1 converts 2-digit-hex-ASCII to 8-bit-binary
- ; Called By: Hex4ToBin2
- ;
- Hex2ToBin1:
- push R0 ; Save register
- rcall Hex1ToBin1 ; Read next char
- brts Hex2ToBin1a ; Error
- swap rmp; To upper nibble
- mov R0,rmp ; interim storage
- rcall Hex1ToBin1 ; Read another char
- brts Hex2ToBin1a ; Error
- or rmp,R0 ; pack the two nibbles together
- Hex2ToBin1a:
- pop R0 ; Restore R0
- ret ; and return
- ;
- ; Hex1ToBin1 reads one char and converts to binary
- ;
- Hex1ToBin1:
- ld rmp,z+ ; read the char
- subi rmp,'0' ; ASCII to binary
- brcs Hex1ToBin1b ; Error in char
- cpi rmp,10 ; A..F
- brcs Hex1ToBin1c ; not A..F
- cpi rmp,$30 ; small letters?
- brcs Hex1ToBin1a ; No
- subi rmp,$20 ; small to capital letters
- Hex1ToBin1a:
- subi rmp,7 ; A..F
- cpi rmp,10 ; A..F?
- brcs Hex1ToBin1b ; Error, is smaller than A
- cpi rmp,16 ; bigger than F?
- brcs Hex1ToBin1c ; No, digit ok
- Hex1ToBin1b: ; Error
- sbiw ZL,1 ; one back
- set ; Set flag
- Hex1ToBin1c:
- ret ; Return
- ;--------------------------------------
- test_Hex4ToBin2:
- pushz
- ldi zl,$60
- clr zh ;z now points to start of buf1
- ldi r16,'0'
- st z+,r16
- ldi r16,'f'
- st z+,r16
- ldi r16,'2'
- st z+,r16
- ldi r16,'3'
- st z+,r16
- ldi zl,$60
- clr zh ;z now points back to start of buf1
- rcall Hex4ToBin2
- popz
- th4: rjmp th4
- ;-------------------------------------
- numberh: ;word not in dictionary. Try to convert it to hex.
- pushz ;algorithm uses z, pity
- movw zl,r24 ;r4,25 = w holds start of current word
- ;z now points eg to '12ab'start. If t=0 then it coverts to real hex
- rcall hex4ToBin2 ;try to convert
- ;above call needs 4 hex digits to emerge with t=0 and binary in r16,17
- ;want this. If t=0 stack r16,17 and carry on interpreting, else emerge with
- ; t=1 and zpointing to first problem char
- brtc gotHex
- ; if here there's a problem that z is pointing to. Bail out of interpret line
- clr STOP
- inc STOP
- ;TODO put routine here that notes the word can't be excuted and it's
- ; not a number. So output ramstring starting at adr = r24,25 and len in r20
- rcall whatq
- rjmp cold ; quit ;outnh **check
- gotHex: ;sucess.Real hex in r16,17
- mypush2 r16,r17 ; so push num onto mystack
- ;maybe we're compiling. If so, push num into dic preceded by a call to stackme_2
- tst STATE
- breq outnh ;STATE =0 means executing
- ; rcall tic
- ; .db "stackme_2" ;has to be in dic before a number. cfa of stackme_2 on stack
- rcall compstackme_2
- ; rcall compileme ;insert "rcall stackme_2"opcode into dic
- rcall comma ;there's the number going in
- outnh:
- popz ; but will it be pointing to "right"place in buf1? Yes now OK
- ret
- ; numberh not working fully, ie doesn't point to right place after action.
- ; also no action if not a number? DONE better save this first.
- ;---------------------------------
- ;eeroutines
- eewritebyte: ;write what's in r16 to eeprom adr in r18,19
- sbic EECR,EEPE
- rjmp eewritebyte ;keep looping til ready to write
- ;if here the previous write is all done and we can write the next byte to eeprom
- out EEARH,r19
- out EEARL,r18 ;adr done
- out EEDR,r16 ;byte in right place now
- sbi EECR,EEMPE
- sbi EECR,EEPE ;last 2 instruc write eprom. Takes 3.4 ms
- ret
- ;test with %!
- ;---------------------------------
- eereadbyte: ; read eeprom byte at adr in r18,19 into r16
- ; Wait for completion of previous write
- sbic EECR,EEPE
- rjmp eereadbyte
- ; Set up address (r18:r17) in address register
- out EEARH, r19
- out EEARL, r18
- ; Start eeprom read by writing EERE
- sbi EECR,EERE
- ; Read data from data register
- in r16,EEDR
- ret
- ;------------------------------
- setupforflashin: ;using here etc get appropriate page, offset,myhere values.
- ; ldi r16,low(HERE)
- ; ldi r17,high(HERE) ;get here, but from eeprom better?
- ; mypush2 r16,r17
- ;above was a problem replace with one line below
- rcall gethere ;HERE = eg 0a12.Now on stk.Comes from eepprom each time
- rcall stackme_2
- .dw 0002
- rcall star ;now have current HERE in bytes in flash. But what is myhere?
- rcall stackme_2
- .db $0040 ;64 bytes per page
- rcall slashMod
- ;offset on top pagenum under. eg pg 0047, offset 0012
- mypop2 r9,r8 ;store offset (in bytes)
- rcall stackme_2
- .db $0040
- rcall star ;pgnum*64 = byte adr of start of flash page
- mypop2 r7,r6
- mypush2 r8,r9 ;push back offset
- rcall stackme_2
- .dw buf2
- nop
- ;at this stage we have offset in r8,r9 (0012). Also byte adr of flash page
- ; start in r6,r7.(11c0) Stk is (offset buf2Start --) (0012 00E0 --). Need to
- ; add these two together to get myhere, the pointer to RAM here position.
- rcall plus ;add offset to buf2 start to get myhere (00f2)
- ; put my here in r4,r5 for time being.
- mypop2 r5,r4 ;contains eg 00f2 <--myhere
- pushz ;going to use z so save it
- movw zl,r6 ;r6,7 have byte adr of flsh pg strt
- pushx ;save x
- ldi xl,low(buf2)
- ldi xh,high(buf2) ;point x to start of buf2
- ldi r18,128 ;r18=ctr. Two flash pages = 128 bytes
- upflash:
- lpm r16,z+ ;get byte from flash page
- st x+, r16 ; and put into buf2
- dec r18
- brne upflash
- ;done. Now have two flash pages in ram in buf2. Myhere points to where next
- ; entry will go. Where's page num?
- popx
- popz ;as if nothing happened
- ret
- ;outsufi: rjmp outsufi
- ;-----------------------------------
- burneepromvars: ;send latest versions of eHERE and eLATEST to eeprom
- ldi r16,low(HERE)
- ldi r17,high(HERE)
- mypush2 r16,r17
- ;up top we have .equ eHERE = $0010
- ldi r16,low(eHERE)
- ldi r17,high(eHERE)
- mypush2 r16,r17
- ;now have n16 eadr on stack ready for e!
- rcall percentstore
- ;send latest versions of eLATEST to eeprom
- ldi r16,low(LATEST)
- ldi r17,high(LATEST)
- mypush2 r16,r17
- ;up top we have .equ eLATEST = $0010
- ldi r16,low(eLATEST)
- ldi r17,high(eLATEST)
- mypush2 r16,r17
- ;now have n16 eadr on stack ready for e!
- rcall percentstore
- ret
- ;-------------------------------------------
- coloncode: ;this is the classic colon defining word.
- rcall setupforflashin ;get all the relevant vars and bring in flash to buf2
- ;rcall dxyz
- rcall relinkcode ; insert link into first cell
- rcall create ;compile word preceeded by length
- rcall leftbrac ;set state to 1, we're compiling
- ;takemeout 'c'
- ;rcall report
- ;takemeout 'c'
- ret ;now every word gets compiled until we hit ";"
- ;-------------------------
- relinkcode: ;put LATEST into where myhere is pointing and update ptr = myhere
- ;also create mylatest
- rcall getlatest ;now on stack
- mypopa ;latest in r16,17
- pushz ;better save z
- movw mylatest,myhere ;mylatest <-- myhere
- movw zl,myhere ;z now points to next available spot in buf2
- st z+,r17 ;problem. Don't work unless highbye first in mem.Why?
- st z+,r16 ;now have new link in start of dic word
- movw myhere,zl ;update myhere to point to length byte. (Not yet there.)
- popz ;restore z
- ret
- ;-------------------------------------------------
- create: ;put word after ":" into dictionary, aftyer link, preceeded by len
- rcall word ;start with x pnting just after ":".End with len in r20, x pointing to
- ; space just after word and start of word in w=r24,25
- pushz ;save z. It's going to be used on ram dictionary
- movw zl,myhere ;z now pnts to next spot in ram dic
- st z+,r20 ; put len byte into ram dic
- mov r18,r20 ;use r18 as ctr, don't wreck r20
- pushx ;save x. It's going to be word ptr in buf1
- movw xl,wl ;x now points to start of word. Going to be sent to buf2
- sendbytes:
- ld r16,x+ ;tx byte from buf1 to
- st z+,r16 ; buf2
- dec r18 ;repeat r20=r18=len times
- brne sendbytes
- sbrs r30,0 ;skip next instruction if final bit lsb = 1
- rjmp downcr
- ;if here lsb = 1 so we're on a padding byte and have to add 1 to get to a 2 byte boundary
- clr r16
- st z+,r16 ;insert padding byte
- ;inc r30
- ;brcc downcr
- ;inc r31 ;add one to z before converting to bytes
- downcr:
- movw myhere,zl ;myhere now points to beyond word in dic
- popx
- popz
- ret ;with word in dic
- ;----------------------------------------------
- leftbrac: ;classic turn on compiling
- clr STATE
- inc STATE ;state =1 ==> now compiling
- ret
- ;------------------------
- compilecode: ;come here with STATE =1 ie compile, not execute. Want to put
- ; eg rcall dup in code in dictionary but not to execute dup. If here
- ; z points to byte address of word
- mypush2 zl,zh
- compileme:
- mypush2 myhere,r5 ;push ptr to RAM dic
- ;next is entry point for eg ' stackme2 already on stack and have to compile
- ldi r16,low(buf2)
- ldi r17,high(buf2) ;start of buf that conatins flash pg in RAM
- mypush2 r16,r17
- rcall minus ; myhere - buf2-start = offset in page
- mypush2 SOFPG,r7 ;push start of flash page address
- rcall plus ;SOFPG + offset = adr of next rcall in dic
- ;if here we have two flash addresses on the stack. TOS = here. Next is there.
- ;want to insert code for "rcall there w"hen I'm at here. eg current debugging indicates
- ; here = $11EB and there is $1012 (cfa of "two"). First compute
- ; relative branch "there - here -2". Then fiddle this val into the rcall opcode
- rcall minus ;that;s there - here. Usu negative.
- ;I got fffffffff..ffe27 for above vals. First mask off all those f's
- rcall two ;stack a 2
- rcall minus ;now have there-here -2 = fe24. When there,here in bytes.
- mypopa ;bring fe26 into r16,17
- clc
- ror r17
- ror r16 ;now a:= a/2
- ldi r18,$ff
- ldi r19,$0f ;mask
- and r16,r18
- and r17,r19
- ; mypush2 r16,r17 ;now fe26 --> 0e26
- ;the rcall opcode is Dxxx where xxx is the branch
- ; mypopa ;bring fe26 into r16,17
- ldi r19, $d0 ;mask
- or r17,r19
- mypush2 r16,r17 ;now have $de26 on stack which is (?) rcall two
- rcall comma ;store this opcode into dic. myhere is ptr
- ret
- ;---------------------------
- stackme_2: ;stacks on my stack next 16bit num. Address of 16bit number is on SP-stack
- ; Used like this stackme_2 0034. Puts 0034 on myStack and increments past number on return stack.
- pop r17
- pop r16 ; they now contain eg 0x0804 which contain the 16bit num
- movw zl,r16 ;z now points to cell that cobtains the number
- clc
- rol zl
- rol zh ;double word address for z. lpm coming up
- lpm r16,z+
- lpm r17,z+ ;now have 16bit number in r16,17
- st y+,r16
- st y+, r17 ;mystack now contains the number
- clc
- ror zh
- ror zl ;halve the z pointer to step past the number to return at the right place
- push zl
- push zh
- ret
- ;------------------------------flash write section--------------------
- do_spm:
- ;lds r16,SPMCSR
- in r16,SPMCSR
- andi r16,1
- cpi r16,1
- breq do_spm
- mov r16,spmcsr_val
- out SPMCSR,r16
- spm
- ret
- ;-------------------------------------------------------------------
- buf2ToFlashBuffer: ;send the 64 bytes, 32 words to flash page <-- Z pnts there.
- push r30 ;save for later spm work.
- push r19
- push xl
- push xh ;used as buf_ctr but may interfere with other uses
- ldi XL,low(buf2) ;X pnts to buf1 that contains the 64 bytes.
- ldi XH, high(buf2)
- ;assume Z is already pointing to correct flash start of page.
- flashbuf:
- ldi buf_ctr,32 ;send 32 words
- sendr0r1:
- ld r16, x+ ;get first byte
- mov r0,r16 ; into r0
- ld r16, x+ ; and get the second of the pair into
- mov r1,r16 ; into r1
- ldi spmcsr_val,01 ;set up for write into spare buffer flash page
- rcall do_spm ;that's r0,r1 gone in.
- inc r30
- inc r30
- dec buf_ctr ;done 32 times?
- brne sendr0r1
- pop xh
- pop xl
- pop r19 ;dont need buf_ctr any more.
- pop r30 ;for next spm job
- ret
- ;--------------------------------------------------------------------------
- ;TODO just have 1 burn routine with buf different
- buf3ToFlashBuffer: ;send the 64 bytes, 32 words to flash page <-- Z pnts there.
- push r30 ;save for later spm work.
- push r19 ;used as buf_ctr but may interfere with other uses
- push xl
- push xh
- ldi XL,low(buf2+64) ;X pnts to buf1 that contains the 64 bytes.
- ldi XH, high(buf2+64)
- ;assume Z is already pointing to correct flash start of page.
- rjmp flashbuf
- ldi buf_ctr,32 ;send 32 words
- sendr0r3:
- ld r16, x+ ;get first byte
- mov r0,r16 ; into r0
- ld r16, x+ ; and get the second of the pair into
- mov r1,r16 ; into r1
- ldi spmcsr_val,01 ;set up for write into spare buffer flash page
- rcall do_spm ;that's r0,r1 gone in.
- inc r30
- inc r30
- dec buf_ctr ;done 32 times?
- brne sendr0r3
- pop r19 ;dont need buf_ctr any more.
- pop r30 ;for next spm job
- ret
- erasePage: ; assume Z points to start of a flash page. Erase it.
- ldi spmcsr_val,0x03 ;this is the page erase command
- rcall do_spm
- ret
- ;------------------------------------------------------------------
- writePage:
- ldi spmcsr_val, 0x05 ;command that writes temp buffer to flash. 64 bytes
- rcall do_spm
- nop ; page now written. z still points to start of this page
- ret
- ;---------------------------------------------------------------
- test_buf2ToFlashBuffer: ;(adr_flashbufstartinBytes -- )
- ; rcall fillBuf
- ; ldi ZH, $10
- ; ldi ZL,$c0 ;z=$01c0. Start of page 67.
- rcall gethere
- rcall double ;want bytes not words for flash adr
- mypopa ;flashPgStart byte adr now in r16,17
- movw zl,r16 ;z <--start of flash buffer
- rcall erasePage
- rcall buf2ToFlashBuffer
- rcall writePage
- herettt:
- rjmp herettt
- ;----------------------
- ; y2. Come here from ";". The pair r6,r7 point to start of flash pg (bytes)
- burnbuf2and3:
- ;takemeout 'U'
- ;ldi r16, 'U'
- ;clr r17
- ;mypush2 r16,r17
- ;rcall emitcode
- ;rcall dlowR
- movw zl,r6 ;z now pnts to start of flash buf
- ;rcall dxyz ;having !!! PROBS take out later
- rcall erasePage
- rcall buf2ToFlashBuffer
- rcall writePage
- ;now going to burn next ram buffer to next flash page. Bump Z by 64 bytes.
- adiw zh:zl,63 ;z now points to start of next flash buffer
- lpm r16,z+ ;advance z pointer by one.adiw only lets max of 63 to be added.
- ;now z points to start of next 64 byte buffer. Time to put buf3 into it.
- rcall erasePage
- rcall buf3ToFlashBuffer
- rcall writePage
- ret
- heret:
- rjmp heret
- ;-------------------------------------------------------------
- updatevars: ;after doing a colon def we have to update sys vars
- ;TODO new version of LATEST is just old version of HERE.
- ;TODO rplace all this code with updatevars2
- ; just shif HERE into LATEST in eeprom to update. Gen. tidy required.
- mypush2 r4,r5 ;put myhere on stack (E8)
- ldi r16,low(buf2)
- ldi r17,high(buf2)
- mypush2 r16,r17 ;start of buf2 on stack (E0)
- rcall minus ;myhere-buf2 = offset. (e8-e0 = 08)
- mypush2 SOFPG,r7 ; push onto stk start adr of flash page
- rcall plus ;SOFG + offset = new HERE
- ;now put also on stack new version of LATEST
- mypush2 r2,r3 ;that's mylatest on stack
- ldi r16,low(buf2)
- ldi r17,high(buf2)
- mypush2 r16,r17 ;start of buf2 on stack (E0)
- rcall minus ;myhere-buf2 = offset. (e8-e0 = 08)
- mypush2 SOFPG,r7 ; push onto stk start adr of flash page
- rcall plus ;SOFG + offset = new LATEST
- ; now have both LATEST (tos) and HERE on stack. Burn these into eeprom
- ;up top we have .equ eLATEST = $0010
- ;But it's too big. In bytes and causing probs. Solution=covert to words
- rcall halve
- ldi r16,low(eLATEST)
- ldi r17,high(eLATEST)
- mypush2 r16,r17
- ;now have n16 eadr on stack ready for e!
- rcall percentstore
- ; TODO the value for HERE is prob in bytes too. Convert to words.
- ;up top we have .equ eLATEST = $0010
- ldi r16,low(eHERE)
- ldi r17,high(eHERE)
- mypush2 r16,r17
- ;now have n16 eadr on stack ready for e!
- rcall halve ;TODO check this
- rcall percentstore
- ret ;with stack clear and new vals for HERE and LATEST in eeprom
- ;----------
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;Now serial stuff starts;;;;;;;;;;;;;;;;;;;;;;;;;
- halfBitTime: ;better name for this delay. Half of 1/600
- ;myDelay1200:
- ;ldi r21,13 ; 13 works for m328 at 16Mhz
- push r20
- push r21
- ldi r21,7 ;try 7 for tiny85 at 8Hmz
- ldi r20,130 ;r20,21 at 130,7 give 833uS. Good for 600baud at 8Mhz
- starthbt:
- inc r20
- nop
- brne starthbt
- dec r21
- brne starthbt
- pop r21
- pop r20
- ret
- ;--------------------------------------------------
- oneBitTime:
- rcall halfBitTime
- rcall halfBitTime
- ret
- ;-------------------------------------------------
- sendAZero:
- ;output 0 on Tx pin
- cbi PORTB,TX_PIN ; send a zero out PB0
- ret
- ;-----------------------------------------------------
- sendAOne:
- ;output 1 on Tx pin
- sbi PORTB,TX_PIN ; send a zero out PB0
- ret
- ;-----------------------------------------------------
- sendStartBit:
- ; send a 0 for one bit time
- rcall sendAZero
- rcall oneBitTime
- ret
- ;-------------------------------------------------------
- sendNextDataBit: ;main output routine for serial tx
- lsr serialByteReg ;push high bit into carry flag then inspect it
- ;originally did lsl but found lsb first.
- brcc gotzero ;if it's a 0 do nothing
- rcall sendAOne ;must have been a 1 in carry
- rjmp down
- gotzero:
- rcall sendAZero ;if here carry was a zero
- down:
- rcall oneBitTime ;so that 1 or 0 lasts 1/600 sec
- ret
- ;-------------------------------------------------------------
- send8DataBits: ; send all bits in serialByteReg
- ldi counterReg,8 ;8 data bits
- sendBit:
- rcall sendNextDataBit
- dec counterReg
- brne sendBit
- ret
- ;--------------------------------------------------------
- sendStopBit:
- ; send a 1 for one bit time
- rcall sendAOne
- rcall oneBitTime
- ret
- ;--------------------------------------------------------
- sendSerialByte: ;main routine. Byte in serialByteReg = r16
- .ifdef testing
- mov r0, r16
- .else
- rjmp usiTxT ;!!seems to work ok.
- push counterReg
- rcall sendStartBit
- rcall send8DataBits
- rcall sendStopBit
- rcall sendStopBit ;two stops
- pop counterReg
- .endif
- ret
- ;**************************************************************
- serialTest0: ;output series of 'AAAA..'s
- ldi serialByteReg, 0x43 ;0x41
- ;rcall usiTxT ;!!
- rcall sendSerialByte
- rcall oneBitTime ; take a rest
- rcall delayOneSec
- ldi r16,$44
- mypush r16
- mypush r16
- rcall emitcode
- rjmp serialTest0 ;continue forever
- ;---------------------------------------------------------
- ;---------Now do SerialRx routines-------------------
- waitForHigh: ;loop til RX is high
- sbis PINB,RX_PIN ;test that pin for set (PB2)
- rjmp waitForHigh ; loop if rx pin is low
- ret
- ;-----------------------------------------------
- waitForLow: ;PRONBLEMs loop til RX is low. FIXED.
- sbic PINB,0 ;test that pin for set (PB2)
- rjmp waitForLow ; loop if rx pin is high
- ret
- ;---------------------------------------------------
- waitForStartBit: ;loop til get a real start bit
- rcall waitForHigh ;should be marking at start
- rcall waitForLow ;gone low. might be noise
- rcall halfBitTime ;is it still low in middle of bit time
- sbic PINB,RX_PIN ;..well, is it?
- rjmp waitForStartBit ;loop if level gone back high. Not a start bit.
- ret ;we've got our start bit
- ;----------------------------------------------------
- checkForStopBit: ;at end, get carry flag to reflect level. Prob if c=0
- rcall oneBitTime ; go into stop bit frame, halfway
- sec ;should stay a 1 in C if stop bit OK
- sbis PINB,RX_PIN ;don't clc if bit is high
- clc ;but only if we have a weird low stop bit
- ret ;with carry flag = stop bit. Should be a 1
- ;-------------------------------------------------------------
- get8Bits: ;get the 8 data bits. No frame stuff
- clr rxbyte ;this will fill up with bits read from RX_PIN
- push counterReg ;going to use this so save contents for later
- ldi counterReg,8 ;because we're expecting 8 databits
- nextBit:
- rcall oneBitTime ;first enter here when mid-startbit
- rcall rxABit ;get one bit
- dec counterReg ;done?
- brne nextBit ;no, round again
- pop counterReg ;yes, finished, restor counter and get out
- ret
- ;---------------------------------------------------------------
- rxABit: ;big serial input routine for one bit
- clc ;assume a 0
- sbic PINB,RX_PIN ; skip nxt if pin low
- sec ;rx pin was high
- ror rxbyte ;carry flag rolls into msb first
- ret
- ;********************************
- getSerialByte: ;big routine. Serial ends up in rxByte
- rjmp usiRxT ; !!!
- push counterReg
- rcall waitForStartBit ;**change
- rcall get8Bits
- rcall checkForStopBit
- pop counterReg
- ret ;with rxByte containing serial bye
- ;----------------------------------------------------
- serialTest1: ;output A then reflect input. Worked OK
- ldi serialByteReg, 0x36 ;0x41
- rcall sendSerialByte
- rcall oneBitTime ; take a rest
- ; rcall getSerialByte
- rcall usiRxT
- mov serialByteReg,rxByte ;output what's been read
- rcall sendSerialByte
- rjmp serialTest1
- ;--------------------------------------------------------
- ;----------Now doing buffer work. Want to and from 64 bytes----------
- fillBuf:
- ldi ZL,low(buf1) ;buf1 is my buffer
- ldi ZH, high(buf1) ;Z now points to buf1
- ldi counterReg,64 ;64 bytes in buffer
- ldi r16,$30
- storeB0:
- st z+,r16
- inc r16
- dec counterReg
- brne storeB0
- herefb:
- ; rjmp herefb
- ret
- ;----------------------------------------------------------
- serialStrOut: ;X points to start of string,r17 has length
- ld serialByteReg, x+
- rcall sendSerialByte
- dec r17 ;got to end of string?
- brne serialStrOut
- ret
- ;----------------------------------
- test_serialStrOut:
- rcall fillBuf
- ldi XL,low(buf1) ;buf1 start of str
- ldi XH, high(buf1)
- ldi r17,64 ;going to send len=r17 bytes
- rcall serialStrOut
- here2:
- rjmp here2
- ;--------------------------------------
- waitForCharD: ;wait til eg a 'D' is pressed then do something.
- ldi serialByteReg, '>' ;0x41
- rcall sendSerialByte
- rcall oneBitTime ; take a rest
- rcall getSerialByte
- mov serialByteReg,rxByte ;output what's been read
- cpi rxByte, 'D'
- brne waitForCharD
- ldi serialByteReg, '*'
- rcall sendSerialByte
- rjmp waitForCharD
- ;-----------------------------------------------------------
- dumpbuf1:
- ;.ifdef livetesting
- ldi XL,low(buf1) ;buf1 start of str
- ldi XH, high(buf1)
- ldi r17,$20 ;going to send len=r17 bytes
- rcall serialStrOut
- ;.endif
- ret
- ;-------------------------------------------------------------
- test_dumpbuf1:
- rcall fillBuf
- rcall getSerialByte ;any one will do.
- rcall dumpbuf1
- rjmp test_dumpbuf1
- ;---------------------------------------------------------------
- rxStrEndCR: ;get a serial string that ends with CR
- clr counterReg
- ldi XL,low(buf1) ;buf1 is where str will go
- ldi XH, high(buf1)
- takemeout 'A'
- upsec:
- rcall getSerialByte
- st x+, rxByte ;char goes into buffer="buf1"
- cpi rxByte,$0d ;is it CR = end of string?
- breq fin
- inc counterReg ;don't go over 64 bytes
- cpi counterReg,124 ;64, extended 29/9/14
- brne upsec ;not too long and not CR so keep going
- rjmp cold ;make clean jump out of mess if input line too long.
- fin:
- ret
- ;---------------------------------------------
- ;------------------------------------------------------------
- rxStrWithLen: ;expect len char char char.. for len chars
- push counterReg
- ldi XL,low(buf1) ;buf1 is where str will go
- ldi XH, high(buf1)
- rcall getSerialByte ; get length bye Must be less than 65
- mov counterReg, rxByte ;save len in counter
- cpi counterReg,65 ;
- brlo allOK ;less than 65 so carry on. Branch if Lower
- ldi counterReg,64 ; if len>64 then len=64. Buffer = buf1 only 64 bytes
- allOK:
- tst counterReg ;zero yet?
- breq finrs
- rcall getSerialByte ;next serial input byte
- st x+, rxByte ;put into buffer
- dec counterReg ;have we done len=counterReg bytes?
- rjmp allOK
- finrs:
- pop counterReg
- ret
- ;---------------------------------------------------------------
- ;-----------------------------now start forth i/o words like emit------------------
- emitcode: ; (n16 --)classic emit
- mypop r16
- mypop r16 ;want lower byte eg in 0041 want just the 41
- rcall sendserialbyte
- ret
- ;------------------------------------------------
- insertret: ;semi has to end new word with ret = $9508 opcode
- pushx ;both xl,xh saved for later
- movw xl,myhere ;myhere points to next available spot in ram dic
- ldi r16,$08
- st x+,r16 ;$08 part goes first
- ldi r16,$95
- st x+,r16 ;ret now in ram. Just tidy pointers
- movw myhere,xl
- popx ;so x back where it was and ret inserted.
- ret
- ;--------------------------------
- equalcode: ;(n1 n2 -- flag) if n1 = n2 flag = 0001 else 0000
- mypopa
- mypopb ; now have TOS in r16,17, underneath that in r18,19
- cp r16,r18 ;low bytes =?
- brne zout ;not equal so go out
- cp r17,r19 ;hi bytes =?
- brne zout ;no, so out
- ;if here both n16's are equal so push a 0001
- rcall one
- rjmp aout ;done
- zout:
- rcall zero ;not = so push a zero
- aout:
- ret ;with a flag on stack replacing to n16's
- ;------------------------------
- ;TODO eliminate below and replace with simpler RAM jmp code.
- calcjumpcode: ;(to from -- opcode_for_rjmp to at from)
- ;used when compiling. What is the rjmp opcode if
- ; we know the from and to adr on stack. ( to fr --)
- ldi r16, low(buf2)
- ldi r17, high(buf2)
- mypush2 r16,r17 ; (to fr $e0 --)
- rcall dup ;t f $e0 $eo
- rcall unrot ;t $e0 fr $e0
- rcall minus ;t $e0 frOffset
- rcall unrot ;frOffset t $e0
- rcall minus ;frOffset toOffset
- ;now apply these offsets in flash buffer. Add them to start of flash buffer adr
- mypush2 SOFPG,r7 ; frOffset toOffset SOFPG
- rcall dup ;frOffset toOffset SOFPG SOFPG
- rcall unrot ;frOffset SOFPG toOffset SOFPG
- rcall plus ;frOffset SOFPG toFlashAdr
- rcall unrot ;toFlashAdr frOffset SOFPG
- rcall plus ;toFlashAdr frFlashAdr
- rcall minus ;to -from give last 3 nibbles in rjmp opcode +1
- ; rcall one
- rcall two ;to - from - 2 when working with bytes
- rcall minus ; now have to - from -2
- rcall halve ;now have jmp length in words. Required for opcode.
- rcall stackme_2
- .dw $0fff
- rcall andd ; now have eg. 0f20. Want Cf20
- rcall stackme_2
- .dw $c000 ;should now have right opcode eg cf20
- rcall orr ;don't forget this !!!!!
- ret ;with correct rjmp kkk on stack. Ready to insert into RAM dic.
- ;-------------------
- stackmyhere: ;( --- adr) put RAM ptr myhere on stack
- mypush2 myhere, r5
- ret
- ;---------------------------
- begincode: ;when using BEGIN just stack current address.No dic entry
- rcall stackmyhere ;put next adr on stack
- ret
- ;----------------------------
- stkmyhere: ;put myhere on the stack, handy
- mypush2 myhere,r5
- ret
- ;-----------------------------------
- stkSOBuf2: ;stack start of buf2. Handy.
- ldi r16,low(buf2)
- ldi r17,high(buf2)
- mypush2 r16,r17
- ret ;with adr of buf2 on stk
- ;--------------------------
- stkSOFPG: ;put start of flash page on stack, In bytes.
- mypush2 SOFPG,r7
- ret ;with start of current flash page's adr on stack.
- ;-------------------------------
- stklatestadr: ;put e-adr of eLatest. Currently 012 in eeprom
- ldi r16,low(eLATEST)
- ldi r17,high(eLATEST)
- mypush2 r16,r17
- ret ;with 012 or adr of eLatest on stk
- ;-------------------------------------
- stkhereadr: ;same as above but for HERE
- ldi r16,low(eHERE)
- ldi r17,high(eHERE)
- mypush2 r16,r17
- ret ;with adr of ehere,current eeprom adr = $010
- ;-------------------------------------------
- updatevars2: ;better version of update vars. Come here after ";"
- ;TODO check this version.DONE and eliminate other one.
- rcall gethere ;the HERE val now on stack. It's a pointer to flash.
- rcall stklatestadr ;usually 012
- rcall percentstore
- ;now with LATEST now containing old HERE. Next fix HERE
- rcall stkmyhere ;current ptr to RAM dic's next free byte
- rcall stkSOBuf2 ;start of buf2 adr
- rcall minus ;gives distance into the buffer
- rcall stkSOFPG ;will add distance to start of flashbuf
- rcall plus ;got flash adr, but in bytes
- rcall halve ;now adr in words
- rcall stkhereadr ;usually %010 in eeprom
- rcall percentstore ;eHERE now updated
- ret ;with vals for HERE and LATEST in eeprom updated after ";"
- ;--------------------
- testOKCR:
- rcall OK
- rcall OK
- rcall CR
- rjmp testOKCR
- ;--------------------
- ;------------------------dump routines _______________
- outnib: ;given $23 in r16, output the 3 as '3' = $33
- push r18 ;going to use this
- andi r16,$0f ; $3a --> $0a
- cpi r16,$0a ;more than 10?
- brge gothexo ;Nibble >= 10 jump down to gothex
- ldi r18,$30 ; add $30 to 0..9
- rjmp doneon
- gothexo:
- ldi r18,$37
- doneon:
- add r16,r18 ;now r16 nibble $03 is a '3'
- rcall sendserialbyte ;print it
- pop r18 ;used this as counter
- ret ;note, it wrecks r16
- ;--------------------------------------------
- d16: ;dump contents of r16. Good for debugging.
- push r16 ;keep contents for later
- push r16 ;need this one after swap
- swap r16 ;$34 wants 3 to come out first
- rcall outnib ;print ascii eg '3'in above if r16 = $34
- pop r16 ;get nice version back eg $34
- rcall outnib ;print the '4'
- pop r16 ;so r16 not wrecked.
- ret ;with r16 printed in ascii
- ;-----------------------------------
- test_d16: ldi r16,$a5
- rcall d16
- ldi r16,$b6
- rcall d16
- rjmp test_d16
- ;--------------------------------
- d1617: ;dump r16 and r17 for debugging purposes
- push r16
- push r17 ;
- push r16 ;just one min
- mov r16, r17
- rcall d16 ;that's r17 gone
- pop r16
- rcall d16 ;and then r16
- pop r17
- pop r16
- ret ;with r17:r16 output in ascii
- ;----------------------------------------
- test_d1617:
- ldi r16,$34
- ldi r17,$1F
- rcall d1617
- rjmp test_d1617
- ;-----------------------------------
- dlowR: ;dump low registers. r0..r15 for debugging
- ;.ifdef livetesting
- push r16
- push r18
- pushx ;macro
- clr xl
- clr xh
- ldi r18,16 ;r18 is a counter
- prlow:
- ld r16,x+ ;assume is x is 0 we'll get r0
- rcall d16
- rcall spacecode
- dec r18
- cpi r18,$07
- breq doeseq7
- tst r18
- brne prlow
- rjmp outprl
- doeseq7:
- ldi r16,'L'
- rcall sendserialbyte
- rcall spacecode
- rjmp prlow
- outprl:
- popx ;macro
- pop r18
- pop r16
- ;B.endif
- ret ;with all the registers r0 ..r15 output in ascii to terminal screen
- ;----------------------------------
- test_dlowR:
- rcall CR
- ldi r16,$02
- mov r0,r16
- ldi r16,$52
- mov r5,r16
- ldi r16,$f2
- mov r15,r16
- rcall dlowR
- rcall CR
- rjmp test_dlowR
- ;-----------------------------
- spacecode: ;output a space
- push r16
- ldi r16,$20
- rcall sendserialbyte
- pop r16
- ret
- ;-------------------------------
- dhighR: ;dump high registers. r18..r25 for debugging
- push r16
- push r17
- pushx ;macro
- ldi xl,18
- ; clr xl
- clr xh
- ldi r17,8 ;r18 is a counter
- prhi:
- ld r16,x+ ;assume is x is 18 we'll get r18
- rcall d16
- rcall spacecode
- dec r17
- cpi r17,5
- breq doeseq21
- tst r17
- brne prhi
- rjmp outprh
- doeseq21:
- ldi r16,'H'
- rcall sendserialbyte
- rcall spacecode
- rjmp prhi
- outprh:
- popx ;macro
- pop r17
- pop r16
- ret ;with all the registers r0 ..r15 output in ascii to terminal screen
- ;----------------------------------
- test_dhighR:
- rcall CR
- ;ldi r18,$88
- ;ldi r19,$19
- ldi r20,$88 ;
- ldi r21,$88
- ldi r22,$22
- ldi r23,$23
- ldi r24,$24
- ldi r25,$25
- rcall dhighR
- rcall CR
- rcall delayOneSec
- rjmp test_dhighR
- ;------------------------------------
- dxyz: ;dump the three pointer regs x,y,z
- push r16
- push r17
- movw r16,xl ;r17:16 gets xh:xl
- rcall d1617
- rcall spacecode
- movw r16,yl
- rcall d1617
- rcall spacecode
- movw r16,zl
- rcall d1617
- rcall spacecode
- pop r17
- pop r16
- ret ;with x,y,z output in ascii as a tripple
- ;--------------------------------------
- test_dxyz:
- rcall CR
- ldi xl,$12
- ldi xh,$34
- ldi yl,$56
- ldi yh,$78
- ldi zl,$9A
- ldi zh,$bc
- rcall CR
- rcall dxyz
- rcall CR
- rjmp test_dxyz
- ;--------------------------------
- ;mystack needs a DEPTH word.
- depthcode: ; (--n16)
- ;leave on mystack the number of items on the stack by bytes.
- movw r16,yl ;now r16,17 has y pointer
- ldi r18, low(myStackStart) ;
- ldi r19, high(myStackStart) ;r18,19 probably contain $1A0, the start of mystack
- mypush2 r16,r17
- mypush2 r18,r19 ;setup for eg $1a6 - $1a0
- rcall minus ;difference=depth = eg 0006 as above.
- ret ; with depth on stack
- ;-----------------------------------------
- test_depthcode:
- ldi r16,$01
- ldi r17,$23
- mypush2 r16,r17
- mypush2 r16,r17
- mypush2 r16,r17
- rcall depthcode
- uptd: mypopa ;depth now in r16,17
- up2: rcall d1617
- rjmp up2
- ;------------------------------------
- dotScode: ;classic .S, print stack non-destructively
- push r16
- push r18
- pushx ;macro
- rcall depthcode ;now depth = len of stk on the mystack top
- ; rcall drop ;stk =eg 0006 . want just len = 06
- mypop2 r17,r18 ;so r18 now has length in bytes we're printing
- tst r18 ;TODO if depth is negative make it 0
- breq outDots
- ldi xl, low(myStackStart)
- ldi xh, high(myStackStart)
- ; movw xl,yl ;use x as temp ptr. Keep y pointing to mystack top
- upds:
- ld r16,x+ ;get tos, Pre-decrement.
- rcall d16 ;print it
- rcall spacecode ;
- dec r18
- brne upds
- outDotS:
- ldi r16, ']'
- rcall sendserialbyte
- rcall spacecode
- popx ;macro
- pop r18
- pop r16
- ret ;with the stack items printed to term screen + ]
- ;-----------------------------
- test_dotScode:
- ldi r16,$A1
- ldi r17,$B2
- mypush2 r16,r17
- mypush2 r16,r17
- mypush2 r16,r17
- rcall dotScode
- rcall drop
- rcall drop
- rcall drop
- uptds:
- rjmp uptds
- ;---------------------------------
- wordscode: ;classic words. List all the words in the dic
- push r16
- push r17
- push r22
- push r23
- push r24
- pushz
- rcall doLatest ;get first link into v
- upwo:
- rcall jmpNextWord ;pnt to link part of next word
- lpm r23,z+
- lpm r22,z+ ;store link into v=r23,24
- lpm r16,z+ ;get len
- andi r16,$0f ;don't want eg $85 to be len when it means immediate len 5.
- clr r17 ;need eg 0006 on stk not 06 later
- mypush2 r16,r17 ;len byte now on mystk
- ;at this stage z points to the start of word name
- mypush2 zl,zh ;flash start adr of string now on mystack
- rcall swapp ; but wrong way round. Want len = TOS
- rcall Sdot ;print the string on the term
- rcall spacecode ;but add space after each word
- tst vl
- brne upwo ;if vl:vh = r23,24 = 0000 finish
- tst vh
- brne upwo
- popz ;
- pop r24
- pop r23
- pop r22
- pop r17 ;TODO macro with multiple pops & pushes
- pop r16
- ret ;with all the words in dic printed
- ;-----------------------------------------------
- clrbuf1:
- ldi ZL,low(buf1) ;buf1 is my buffer
- ldi ZH, high(buf1) ;Z now points to buf1
- ldi counterReg,64 ;64 bytes in buffer
- ldi r16,$30
- storecl:
- st z+,r16
- inc r16
- dec counterReg
- brne storecl
- ret
- ;-----------------------
- updatevarptrcode: ;update varptr currently at eeprom's 0016. Add 2 to its contents.
- rcall getvarptr ;eg 0160 in ram
- rcall two
- rcall plus ;now is eg 0162
- rcall varptradr ;usually 0016 in eeprom
- rcall percentstore ;should be called estore ie e!
- ret ;with ptr val = old ptrval + 2
- ;-------------------------
- variablecode: ;big word called each time variable is declared
- rcall coloncode ;does all the create work in buf
- rcall tweakvarbit ;make bit 6 a 1. All vars have this.
- rcall getvarptr ;put eg 0162 on stack. Address of next RAM var place.
- rcall compstackme_2 ;put stackme_2 as first code when called
- rcall comma
- rcall updatevarptrcode ;add 2 to varptr
- rcall semi ;finish off and burn to flash
- ret ;with variable created.
- ;----------------------------------
- considercode: ;having probs with findword going awol. Need another debug routine.
- .ifdef livetesting
- rcall CR
- takemeout '[' ;just little mark for Id
- rcall dhighR ;
- ;Used when we've found a word.Starting at w(r24,25) length in r20. x points to space just past word.
- ; u = r22,23
- takemeout ']' ;just little mark for Id
- .endif
- ret
- ;-------------------------
- ifcode: ;classic IF
- rcall tic
- rcall zerobranch
- rcall comma
- rcall stackmyhere
- rcall zero
- rcall comma
- ret ;with (rcall zerobranch, 0000) in dictionary in RAM
- ;-------------------new parts to below----
- housekeeping: ;cold start routines
- ldi r16, 0xfe ;!!! 0xf9 ;PORTB setup
- out DDRB,r16 ;
- nop
- ldi r16, $ff
- out PORTB,r16
- .IFDEF testing ;testing = simulating on avrstudio4
- .ifndef firsttime ;just want to burn vars on first cold start
- nop
- rcall burneepromvars ;maybe a simple flag is better ?
- .equ firsttime = 1
- .endif
- .ENDIF
- clr STATE
- rcall OK ;two OK}s mean cold start.
- ldi xl,$a0
- ldi xh,$01 ;point to ram VARS
- clr r16
- st x+,r16
- st x+,r16 ;that's FBFlag mae 0.(ie use serialfill, not block fill)
- st x+,r16 ;lower byte of FBPointer ie the 00 of $1c00.
- ldi r16,$1c
- st x+,r16 ;so now have $1c00 in FBPntr. Pnts to start of BLOCK.
- rcall updateevar
- ret ;with the housekeeping done
- ;-------------------------------
- blockfillcode: ; pull in one def from BLOCK at $1c00 (bytes)
- rcall FBPtr ;now have $01a2, holds ptr to last 1K of flash, on stk
- rcall fetch ;get ptr on stack. Start at $1c00 (bytes) in flash
- mypop2 zh,zl ;point to first (or next) def with z
- ldi xl,low(buf1)
- ldi xh,high(buf1) ;x points to buffer, just like serial fill
- upbfc:
- lpm r16,z+ ;get char in BLOCK def
- tst r16 ;it might be a zero, pad bytes have been added sometimes
- brne downbfc ;get out if not a zero
- gota0:
- ldi r16,$20 ;if it's a zero, change it to a space
- downbfc: ;TODO should really count chars and stop at,say,120
- st x+,r16 ;flash byte now in AM buf1
- cpi r16,$0d ;all defs end in CR. Got to end yet?
- brne upbfc ;keep going if it's just a char != $0d.
- mypush2 zl,zh ;finished so save pointer for next def
- rcall FBPtr ;put $01a2 on stack, adr of ptr to last k defs
- rcall store ;z-->FBPtr
- clr STOP ;stop flag still going from last def or word
- ret ;with one more def placed into buf from block. This gets interpreted in normal way.
- ;--------------------------------------------
- test_rs: ;test the rs. word that prints ram strings
- rcall fillbuf
- ldi r16,$60
- clr r17
- mypush2 r16,r17 ;pnt to buf1
- ldi r16,10 ;len
- mypush2 r16,r17
- rcall rs
- rcall qmark ;test qmark too
- trs: rjmp trs
- ;---------------------------
- whatq: ;outputs word? when word not in dic and not a number
- mypush2 r24,r25 ;adr of strange word during numberh
- mypush r20 ;the len
- clr r16
- mypush r16 ;topup. Now have req (adr len --) on stack. To to call rs.
- rcall rs
- rcall qmark
- ret
- ;---------------------------------------
- findfirstvarcode: ;( -- adr16) ;go down the dictionary finding first var,(bit6 of len set)
- pushz
- rcall dolatest
- upffv:
- rcall jmpNextWord
- lpm r23,z+
- lpm r22,z+ ;link for next word goes into r22,23 = v
- ;lpm r16,z+
- ;lpm r16,z+
- lpm r16,z+ ;now point to len. Len in r16
- sbrs r16,6
- rjmp upffv ;if bit 6 is clear (not a var) go to up
- andi r16, $0f ;mask off top nib to give real len
- clc ;going to add
- add zl,r16 ;step over name of var
- ;had problems here with padding byte. So now, if padding byte inc Z but carry on
- lpm r16,z ;does z pnt to padding byte?
- tst r16 ;not sure find out
- brne contffv ;non-zero so not a padding byte
- ;if here we've hot a padding byte so do a dummy load to advance z over this byte
- lpm r16,z+
- contffv:
- inc zl
- inc zl
- brcc downffv ;maybe zl has over flowed
- inc zh ;only if overflow
- downffv:
- lpm r16,z+ ;z points to ram adr after stackme2
- lpm r17,z ;now have RAM adr of var eg $01a4
- mypush2 r16,r17
- popz
- ret ;with ram adr of top var on mystack
- ;------------------------------------------
- strout: ; comes in dic like stackme-2 with structure assumptions. Should be followed by
- ; len then a string of len chars. like this /strout/len/c c c c / other rcalls. Strout puts adr of
- ; str on mstack and len then calls S. to print the string . It also makes reurn adr pnt to other.
- pop zh ;hope we don't have to save z
- pop zl ;check on order. Z now pnts to len
- clc ;need to double z to get byte adr
- rol zl
- rol zh
- lpm r16,z+
- lpm r17,z+ ;r16,17 now have len. z points to str
- mypush2 r16,r17 ;len on mystack
- rcall dup ; ( l l --)
- mypush2 zl,zh ; ( l l adr --) adr is of str /c c c ../ above
- rcall dup ; ( l l adr adr --)
- rcall rot ; ( l adr adr l --)
- rcall plus ; ( l adr (adr+l) --) adr + l = adr of "other rcalls" above
- rcall halve ;adr going onto ret stk needs to be word, not byte adr
- brcc downstro ; clear carry means halve exact, not 00 padding bytes
- rcall one
- rcall plus ;add 1 to skip over padding byte of carry set by halve
- downstro:
- mypopa ; adr of other in r16,17. stk = ( l adr --)
- push r16 ;check order
- push r17 ; return adr now points to "other"
- rcall swapp ; now ( adr l--) ready for next line
- rcall Sdot ; print the string
- ret ; after string print to other, just past the string
- ;-----------------------------------------------
- tweakvarbit: ;a bit like immediate, but sets bit 6 when vars are being created
- ; based on immediate. Comes right after variable's name is created by coloncode.
- mypush2 r2,r3 ;this is mylatest. pnts to link of new word
- rcall two
- rcall plus ;jmp over link to pnt to len byte
- pushx ;better save x
- mypop2 xh,xl ;x now pnts to len byte
- ld r16,x ; and put it into r6
- ldi r18,$40 ;mask
- or r16,r18 ;eg 03 --> 43 in hex
- st x,r16 ;put len byte back
- popx ;back where it was
- ret ;done now newly created word is a variable
- ;---------------------------------------
- nextcode: ;( var-adr--) Used in for .. next
- rcall dup ; now have (adr adr --). One is for the store coming up
- rcall fetch ;assumes adr of var already on stack. for ... var next
- rcall one ;decrement var and say if it's 0 yet with a flag
- rcall minus ; now have (adr {val-1} --)
- rcall dup ; ( adr val val
- rcall rot ; ( val val adr --)
- rcall store ;reduced val now in var
- ;but reduced val left on the stack for next instruction
- rcall zeroequal ;this leaves a flag for 0 branch. Think I'd prefer <=
- ret
- ;----------------------------------
- compnextcode: ;compiles above nextcode. Used in for... var next loops
- ldi r16,low(nextcode)
- ldi r17,high(nextcode)
- mypush2 r16,r17 ;in words need to *2 to convert to bytes
- rcall two
- rcall star
- rcall compileme
- ret ;with "rcall nextcode"in next
- ;------------------------------------------------------
- forg_old: ;start of forget TAKE OUT replaced by forg1 below
- rcall word
- rcall findword ;now x points to cfa of word
- mypush2 zl,zh
- rcall dxyz
- ; sbrc r20,0 ;is the length=r20 even? NOT NEEDED TAKE OUT
- rjmp carryonfo
- leneven:
- pushz ;one cotains stackme_2 which wrecks z
- rcall one
- popz
- rcall minus ;z<--z-1 if len even and so 0 padding bit needs jumping
- carryonfo:
- rcall dxyz ;TAKE out later
- clr r17
- mypush2 r20,r17 ;(z len --)
- rcall minus ;z-len = start of name
- ldi r16,03 ;three steps back = link word
- clr r17 ;got unclrd by minus
- mypush2 r16,r17
- rcall minus ;z, on stack, now pints to link word
- rcall dup ;( z z --)
- mypop2 zh,zl ;( z --) new HERE=z
- lpm r16,z+ ;inside link is link for prev word ie new LATEST
- lpm r17,z ;r16,17 have now new latest
- mypush2 r17,r16 ;usual order on stk ok. This is a word adr. But newHERE in bytes so..
- ;now have on mystk ( newHERE newLATEST) ready to be burned into eeprom
- rcall swapp ;( L(word) H(bytes) --)
- rcall halve ;( L H --) both in words
- rcall hereadr ;( L H 0010--) where 0010 is current eeprom adr for HERE
- rcall estore ;(L --) but new here is now in eeprom
- rcall latestadr ;( L 0012 --) currently
- rcall estore ; newlatest 0012 e!. Done. Both new L and H in eeprom
- ret ;with new values for latest and here put into eeprom homes. TODO sort out firstvar here
- ;-------------------------------------------
- constantcode: ;( n16 --) used when constant declared. Just puts val onto stack
- rcall coloncode ;most of this is take straight from variablecode without complications
- rcall compstackme_2
- rcall comma ;there's the stack value going into def
- rcall semi ;sends compiled code to flash
- ret ;used like 0123 constant myconst
- ;------------------------------------------------
- forg1: ;start of forget
- rcall word
- rcall findword ;now x points to cfa of word
- ;check here that the word is found. Otherwise crash out to cold
- ; sbrc r20,0 ;is the length=r20 even?
- tst r15 ;is FOUND=r15 true? ie forget xx, does xx exist in dic
- brne carryonf
- rcall whatq ;xx non-existing word. Output xx? then jmp to cold
- rjmp cold
- ; rjmp carryonf
- ;leneven:
- ; rcall one
- ; rcall minus ;z<--z-1 if len even and so 0 padding bit needs jumping
- carryonf:
- mypush2 zl,zh
- clr r17
- mypush2 r20,r17 ;(z len --)
- rcall minus ;z-len = start of name
- ldi r16,03 ;three steps back = link word
- clr r17 ;got unclrd by minus
- mypush2 r16,r17
- rcall minus ;z, on stack, now pints to link word
- rcall dup ;( z z --)
- mypop2 zh,zl ;( z --) new HERE=z
- lpm r16,z+ ;inside link is link for prev word ie new LATEST
- lpm r17,z ;r16,17 have now new latest
- mypush2 r17,r16 ;usual order on stk ok. This is a word adr. But newHERE in bytes so..
- ;now have on mystk ( newHERE newLATEST) ready to be burned into eeprom
- rcall swapp ;( L(word) H(bytes) --)
- rcall halve ;( L H --) both in words
- rcall hereadr ;( L H 0010--) where 0010 is current eeprom adr for HERE
- rcall estore ;(L --) but new here is now in eeprom
- rcall latestadr ;( L 0012 --) currently
- rcall estore ; newlatest 0012 e!. Done. Both new L and H in eeprom
- ret ;with new values for latest and here put into eeprom homes. TODO sort out firstvar here
- ;----------------------------------------------------
- maskcode: ;(n16 -- mask_16) 3 mask gives 0008 ie 0000 1000 in low byte, bit 3 is set. Handy
- mypopb ;n16 <--r18
- ldi r16,01 ;start of mask. Going to shift the one.
- upmc:
- tst r18 ;ask: got to 0 yet?
- breq outmc ;yes, quit
- lsl r16 ;shift that 1 , 1 bit to the left
- dec r18 ;counter
- rjmp upmc
- outmc:
- clr r17
- mypush2 r16,r17 ;stack the mask
- ret ;with
- ;--------------------------
- setbitcode: ; (n16 n16 --) (bit_no, reg_no --) eg 0003 0038 setbit sets bit 3 of PORTB
- pushx
- mypop2 xh,xl ;ioadr now in x . Stck now ( mask_num --)
- rcall maskcode ;(mask --)
- mypopb ;mask now in r18
- ld r16,x ;get io reg contents, or RAM contents
- or r16,r18 ;makes bit at mask-position a 1 in r16
- st x, r16 ;send amended val back to RAM byte
- popx
- ret ;with one particular bit set in RAM/IO byte
- ;-----------------------------------
- clrbitcode: ; (n16 n16 --) (bit_no, reg_no --) eg 0003 0038 clrbit clrs bit 3 of PORTB
- pushx
- mypop2 xh,xl ;ioadr now in x . Stck now ( mask_num --)
- rcall maskcode ;(mask --)
- mypopb ;mask now in r18
- com r18 ;make eg 00001000 into complement = 11110111
- ld r16,x ;get io reg contents, or RAM contents
- and r16,r18 ;makes bit at mask-position a 0 in r16
- st x, r16 ;send amended val back to RAM byte
- popx
- ret ;with one particular bit cleared in RAM/IO byte
- ;-------------------------------------
- bitfetchcode: ; used by bit@ (n1 n2 -- flag) n1 is bit num and n2 is RAM/IO adr
- pushx
- mypop2 xh,xl ;that's the io adr now in x
- rcall maskcode ; now have bit mask on stack
- mypopb ;mask now in r18
- ld r16, x ;get RAM contents or IO contents
- and r16,r18 ;mask mostly zeros so will bit 0 but maybe 1 bit set
- tst r16
- breq gotz ;go and stack a 0
- got1:
- rcall one
- rjmp outbf
- gotz:
- rcall zero
- outbf:
- popx
- ret ;with a 1 or zero on stk depending on bit n1 in RAM/I
- ;---------------------------------------------------
- ;----------some timer0 routines---------------------------
- blinkTimer:
- rcall setUp
- ;rcall showCounters
- rcall waitForPinHigh
- ;rcall showCounters
- rcall waitForPinLow
- ;inc r17
- ;rcall showCounters
- rcall startTim0u
- rcall chkInp
- rcall stopTim0
- rcall showCounters
- ; rcall waitForever
- rjmp blinkTimer
- ;--------------------------------------------
- setUp:
- CBI DDRB,1 ;clr PORTB1 FOR inPUT
- clr r17
- clr r18
- clr r19 ;counters
- ;clr r16
- out TCNT0,r17 ;always start with clean count
- ret
- ;----------------------------------------------
- startTim0:
- LDI r16,0b0000_0101 ;SET TIMER PRESCALER TO /1024, 03 is /64
- OUT TCCR0B,r16
- ret ;with timer now started
- ;-----------------------------------------------
- stopTim0:
- LDI r16,0b0000_0000 ;Stop TIMER
- OUT TCCR0B,r16
- ret ;with timer now stopped
- ;----------------------------------------------------------
- waitForPinHigh:
- sbis PINB,1
- rjmp waitForPinHigh
- ret ;when pin PB1 goes high
- ;--------------------------------------------------
- waitForPinLow:
- ; ldi zl,0x36
- ; clr zh
- ; ld r16,z
- ;rcall d16
- ; rcall spacecode
- sbic PINB,1
- rjmp waitForPinLow
- ret ;when pin PB1 goes low
- ;-------------------------------------
- chkInp: ;main loop. Come here after pin gone low
- sbic PINB,1 ;loop until pin PB1 goes high
- rjmp outci
- in r16,TIFR ;TOV0 goes high when TCNT0 overflows
- andi r16, 0b0000_0010 ;TOV0
- breq chkInp ;mostly take this branch
- overflow:
- ldi r16,0b0000_0010
- out TIFR,r16 ;push TOV0 flag back down by writng 1 to it.
- inc r17 ;overflow of TCNT0, therefore, click counters
- brne chkInp ;r17 not overflowing so chk pin all over again
- inc r18 ;if r17 becomes ff +1 click r18
- brne chkInp ;no overflow so start again with loop
- inc r19 ;sometimes, might need this for very long delays.
- rjmp chkInp ;if r19 overflows, bad luck, do nothing
- outci:
- ret ;with counters full but need to stop clock soon
- ;-----------------------------------------
- showCounters: ;after clock has stopped need to see their values
- rcall CR
- in r16,TCNT0
- ;show r16,r17
- rcall d1617
- rcall space
- movw r16,r18
- ;show r16,r17
- rcall d1617
- ret ; with TCNT0,r17,18,19 all showing.
- ;--------------------------------------------------
- waitForever:
- nop
- rjmp waitForever
- ret ;never taken. Jump on spot
- ;---------------------------------------------
- wdscode: ;list just a few words for testing purposes
- push r16
- push r17
- push r22
- push r23
- push r24
- push r6
- pushz
- ldi r16,$0c ;r6 is counter for words
- mov r6,r16 ;stop after 12 words. Best for testing.
- rcall doLatest ;get first link into v
- upwrd:
- rcall jmpNextWord ;pnt to link part of next word
- lpm r23,z+
- lpm r22,z+ ;store link into v=r23,24
- lpm r16,z+ ;get len
- andi r16,$0f ;don't want eg $85 to be len when it means immediate len 5.
- clr r17 ;need eg 0006 on stk not 06 later
- mypush2 r16,r17 ;len byte now on mystk
- ;at this stage z points to the start of word name
- mypush2 zl,zh ;flash start adr of string now on mystack
- rcall swapp ; but wrong way round. Want len = TOS
- rcall Sdot ;print the string on the term
- rcall spacecode ;but add space after each word
- dec r6 ;different from 'words'. Stop after 5
- breq outwds
- tst vl
- brne upwrd ;if vl:vh = r23,24 = 0000 finish
- tst vh
- brne upwrd
- outwds:
- popz
- pop r6
- pop r24
- pop r23
- pop r22
- pop r17 ;TODO macro with multiple pops & pushes
- pop r16
- ret ;with all the words in dic printed
- ;-----------------------
- test_strout:
- rcall strout
- .dw $05
- .db "abcde"
- ret
- ;---------------------------------------------
- insertreti: ;semireti has to end new word with reti = $9518 opcode
- pushx ;both xl,xh saved for later
- movw xl,myhere ;myhere points to next available spot in ram dic
- ldi r16,$18
- st x+,r16 ;$18 part goes first
- ldi r16,$95
- st x+,r16 ;ret now in ram. Just tidy pointers
- movw myhere,xl
- popx ;so x back where it was and reti inserted.
- ret
- ;----------------------------------
- interrupt_0: ;experiment for interrupts
- ;global interrupt enable
- lds r16, $005b ;set PCIE, bit 5 of GMSK
- ori r16,0b0010_0000 ; in order to enable pin change ints
- sts $005b,r16 ;pin changes now enable
- sbi PCMSK,01 ;enable PINB1 for pin change int
- ;assume the vector for pin change interrupts is pointing to ISR yhat ..
- ; ends with reti. Then, when this is run we should see that routine invoked when pin changes.
- sei
- ret
- herei0:
- rjmp herei0
- ;----------------------------
- testT0_ISR0: ;take out later
- inc r18
- brne downt0
- inc r19
- brne downt0
- inc r20
- ;takemeout 'I'
- downt0:
- reti
- ;------------------------------------
- startT0_0: ;just experimenting with getting T0 interrupts
- sei ;need global int
- lds r16,$0059 ;0x39=TMSK(io), bit 1 controls timer0 overflow int
- ori r16,0b000_0010 ;bit 1 =1 => t0 over int enabled
- sts $0059, r16
- rcall interrupt_0 ;set up pinchange interrupt
- ldi zl,$60
- ldi zh,0 ;x points to buf1. Going to store values there
- CBI DDRB,1 ;clr PORTB1 FOR inPUT
- clr r17
- clr r18
- clr r19 ;counters
- out TCNT0,r17 ;always start with clean count
- ;startTim0:
- LDI r16,0b0000_0101 ;SET TIMER PRESCALER TO /1024, 03 is /64
- OUT TCCR0B,r16
- ;things have started and ISR will kick in every overflow. Plan: watch r18. It should
- ; .. climb to 0x20 about every second with 8Mhz clock and 1024 prescale.
- ;so if r18 =0x20, do something, like output a char. Reset counters too.
- ;takemeout 'A'
- chkr18:
- tst r6 ;is there a new val
- breq chkr18
- clr r6 ;if so print it (about once per sec)
- ld r16,z
- mov r17,r6
- ; rcall qmark
- ; rcall d1617
- nop
- rjmp chkr18
- ret ; never taken
- ;------------------------------------------------
- pcISR2: ;pin change interrupt comes here for ISR
- ldi r16,$01
- mov r6,r16 ;a flag. There's a new value.
- lds r16,$0052 ;get TCNT0
- mov r17,r18 ;save where we got to do TCNT0 display later
- clr r18
- clr r19
- sts $0052,r18 ;clr TCNT0
- rcall d1617 ;show count
- rcall space
- reti
- ;----------------------------------------------
- TOVO_ISR: ;Timer0 ISR. Simple.
- inc r5
- lds r6,$0075 ;new counter;
- inc r6
- sts $0075,r6
- reti
- ;--------------------------------------
- PC_change_ISR: ;come here everytime a pin change occurs with all approp ints enabled
- rcall stopTim0
- sts $0070,r5 ;save the val of num of TOVOs
- in r16,TCNT0
- sts $0071,r16
- lds r16,$0075
- sts $0074,r16 ;save counter2 in $74
- clr r5 ;clear the counter. Will start again when StartTim0 invoked
- sts $0072,r5 ;flag = 0 then there's a pin change
- out TCNT0,r5 ;clr TCNT0. So both counters reset.
- sts $0075,r5 ;reset counter
- ; sts $0075,r5 ;clear other counter
- rcall startTim0 ;tick until next pin change
- reti
- ;---------------------------------------------
- quickT0: ;trying to get fastest int driven timer
- rcall setupqt ;called only once
- loopqt:
- lds r16,$0072 ;flag
- tst r16
- brne loopqt ;mostly loop back up. But if there's a pinchange...
- ldi r16,1
- sts $0072,r16 ;flag. When cleared by pinchange, there's a reading.
- lds r16,$0074 ;number of TCNT0 overflows stored in 0074.
- rcall d16 ;output main counter, usu 1E for 1sec and div 1024
- lds r16,$0071 ;TCNT0 contents stored in 0071
- rcall d16 ;output TCNT0. about $60 with current int software.
- rcall space
- rjmp loopqt
- ret ;never taken
- ;----------------------------------------
- setupqt:
- lds r16,$0059 ;0x39=TMSK(io), bit 1 controls timer0 overflow int
- ori r16,0b000_0010 ;bit 1 =1 => t0 over int enabled
- sts $0059, r16
- lds r16, $005b ;set PCIE, bit 5 of GMSK
- ori r16,0b0010_0000 ; in order to enable pin change ints
- sts $005b,r16
- sbi PCMSK,01 ;enable PINB1 for pin change int
- ;pin changes now enable
- sei ;global int-enable flag
- ret
- ;-----------------------------
- TOVO_ISR_1d0: ;Timer0 ISR. Simple.
- ; inc r5
- push r6
- lds r6,$01d0 ;new counter;
- inc r6
- sts $01d0,r6
- pop r6
- reti
- ;-------------------------------
- TOVO_ISR_k0: ;Timer0 ISR. Simple.
- push r6
- lds r6,$01a4 ;varaiable k0 is counter
- inc r6
- sts $01a4,r6
- tst r6 ;needed? sts sets no flags
- brne outTOVO
- lds r6,$01a5
- inc r6
- sts $01a5,r6
- outTOVO:
- pop r6
- ; inc r5
- ; rcall k0
- ; rcall incc
- reti
- ;----------------------
- testio:
- rcall OK
- rcall OK
- rcall OK
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- rcall delay100ms
- ;rjmp serialTest0 ;the two routines here worked ok at 600 baud using new IO pins
- rjmp serialTest1
- rjmp testio
- delayOneSec:
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- rcall delay100ms
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- rcall delay100ms
- rcall delay100ms ;want plenty of burn time before doing eeprom work
- rcall delay100ms
- ret
- ;88888888888888888888888888888888888888888888888888--------------------------------------
- ;99999999999999999999999999999999999999999999999999999999999999999999999999999999999999
- .include "tn85def.inc" ;usi2l: This version is cut down and works at 9600 baud
- ;again:
- ldi r16, low(RAMEND)
- out SPL, r16
- ldi r16,high(RAMEND)
- out SPH, r16
- top:
- ldi r16,$ff
- out DDRB,r16
- out PORTB,r16
- ldi r19,(1<<USIWM0)|(0<<USICS0) ;need this otherwise msb not initially joined to D0
- out USICR,r19
- rjmp test_usiRxT
- ;----------------------------------------
- reverseBits: ;r16 gets reversed
- push r17
- push r18
- ldi r18,8
- ldi r17,0
- uprb:
- lsl r16
- ror r17
- dec r18
- brne uprb
- mov r16,r17
- pop r18
- pop r17
- ret
- ;-----------------------
- split62: ;split r16 into two bytes, r16 and r17 where r16 contains first 6 bits preceded by
- ldi r17,$ff
- clc
- ror r16
- ror r17
- sec
- ror r16
- ror r17
- ret
- rjmp split62
- ;-------------------------
- waitForPin0Low:
- sbic PINB,0
- rjmp waitForPin0Low
- ret ;when pin PB1 goes low
- ;------------------------
- waitForPin0High:
- sbis PINB,0
- rjmp waitForPin0High
- ret ;when pin PB1 goes high
- ;-------------------------------------
- startTim0u:
- LDI r16,0b0000_0010 ; 2=/8 3=/64 4 = /256 5 /1024 SET TIMER PRESCALER TO , 03 is /64
- OUT TCCR0B,r16
- ret ;with timer now started
- ;-----------------------------------------------
- stopTim0u:
- LDI r16,0b0000_0000 ;Stop TIMER
- OUT TCCR0B,r16
- ret ;with timer now stopped
- ;-----------------------------------------------
- USITransfer_Fast3: ;USES TIMER0:
- out USIDR,r16
- ldi r19,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK)
- ldi r18,8
- rcall startTim0u
- ; LDI r16,0b0000_0100 ; 4 = /256 2=/8 3=/64 5= /1024 2=/8 SET TIMER PRESCALER TO /1024,
- ; OUT TCCR0B,r16 ;start tim0
- upt23:
- rcall clrTCNT0
- rcall waitTilTim0Fin
- out USICR,r19
- dec r18
- brne upt23
- ret
- ;---------------------------------------
- clrTCNT0:
- clr r16
- out TCNT0,r16
- ret
- ;---------------------***--
- waitTilTim0Fin: ;wait til timer 0 counts up to top value
- in r16,TCNT0
- cpi r16,104 ;Now try 104 /8 9600? Best speed I think. Works at 52 /8 19200. But
- ; not at 26 /8 38
- brne waitTilTim0Fin
- ret
- ;-----------------------
- waitHalfBit: ;wait til timer 0 counts to half above
- rcall clrTCNT0 ;this took 2 days to insert.
- rcall startTim0u
- whb:
- in r16,TCNT0
- cpi r16,104/2
- brne whb
- rcall stopTim0u
- ret ;used during start bit rx
- ;-----------------------------------------------------
- usiTxT: ;uses timer0. Byte to be sent is in r16
- push r17
- push r18
- push r19
- ldi r17,$ff ;make r1 an output as this stage. Can interfere with Rx
- out DDRB,r17
- rcall reverseBits ;needed
- rcall split62 ;now have (10 + 6lsbs) + (2 msbs + 6Stops) in r116,r17
- rcall USITransfer_Fast3 ;there's the r16 gone
- mov r16,r17
- rcall USITransfer_Fast3 ;and the r17.
- LDI r16,0b0000_0000 ;stop timer,
- OUT TCCR0B,r16
- pop r19
- pop r18
- pop r17
- ret ;with r16 having been sent via USI Tx
- ;--------------------------------------
- usiRxT: ;input a byte serially via PB0 using usi
- push r17
- push r19
- ldi r16,$fc
- out DDRB,r16 ;make both Tx,Rx inputs to stop interference
- rcall waitForPin0High
- rcall waitForPin0Low ;2
- rcall waitHalfBit
- ldi r16,$ff
- out PORTB,r16 ;fill usi data reg with 1's so no start bits come out while shifting
- rcall USITransfer_Fast3 ;do 8 shifts into usidr from PB0. Emerge with byte in usidr
- in r16,USIDR
- rcall reverseBits ;needed
- mov r18,r16 ;!! so both r16 and r18 contain the rx byte. Needed for old rx RXBYTE routines.
- ; rcall usiTxT ;display byte.
- pop r19
- pop r17
- ret
- ;------------------------
- test_usiRxT: ;worked
- ldi r16,$32
- rcall usiTxT
- rcall usiRxT ;the rx byte ends up in r16 so ..
- rcall usiTxT ;display byte.
- rjmp test_usiRxT
- ;-----------------------
- serialTest3: ;output A then reflect input. Worked OK
- ldi serialByteReg, 0x36 ;0x41
- rcall usiTxT ;sendSerialByte
- rcall oneBitTime ; take a rest
- ; rcall getSerialByte
- rcall usiRxT
- mov serialByteReg,rxByte ;output what's been read
- rcall usiTxT ; sendSerialByte
- rjmp serialTest3
- ;--------------------------
- serialTest4: ;works with old routines now pointing to usi ones.Good!
- ldi serialByteReg, 0x34 ;0x41
- rcall sendSerialByte ;usiTxT ;sendSerialByte
- rcall oneBitTime ; take a rest
- rcall getSerialByte
- ;rcall usiRxT
- mov serialByteReg,rxByte ;output what's been read
- rcall sendSerialByte
- ; rcall usiTxT ; sendSerialByte
- rjmp serialTest4
- fetchTest: ;cfetch etc not working well. Why?
- ;push x
- ldi r18,$50
- ldi r19,$00
- mypush2 r18,r19
- ldi xl,$77
- ldi xh,$00
- mypush2 xl,xh
- rcall store
- st x,r18
- ld r19, x
- rcall dumpbuf1
- rcall delayOneSec
- rjmp fetchTest
- ;------------------------------------------
- dumpbuf2: ;copied from dumpbuf1 but avoids lots of dumps extraneous to this one
- ;.ifdef livetesting
- ;rcall fillBuf
- pushx
- ldi r16,$77
- ldi r17,$00
- mypush2 r16,r17
- ; ldi xh,00
- ; ldi xl,$77
- mypop2 xh,xl
- ldi r16, $41
- st x,r16
- ldi XL,low(buf1) ;buf1 start of str
- ldi XH, high(buf1)
- ldi r17,$40 ;going to send len=r17 bytes
- rcall serialStrOut
- popx
- ;.endif
- ret
- ;----------------
- dumpVarSpaceCode:
- pushx
- ldi XL,low(varSpace) ;buf1 start of str
- ldi XH, high(VarSpace)
- ldi r17,$40 ;going to send len=r17 bytes
- rcall serialStrOut
- popx
- ;.endif
- ret
- ;----------------------------
- TCNT0Fetch: ;(--n)
- ;lds r16,$0052 ;get TCNT0
- in r16,$32
- clr r17 ;
- mypush2 r16,r17
- ret ;with TCNT0 on stack
- ;---------------------
- TCNT0Store: ;(n--)
- ;assume value to be stored is on mystack. Only lsByte will be stored
- mypopa ;lsbyte now in r16. r17 thrown away
- ;sts $0052,r16 ;put this byte into TCNT0
- ; ldi r16, $67
- out $32,r16
- ret
- ;-----------------------
- test_tfs: ; test above ,temp
- ; rcall zero ;put something on the stack
- ldi r16,$12
- ldi r17,$23
- mypush2 r16,r17
- ; rcall one
- rcall TCNT0Store
- rcall TCNT0Fetch
- rcall emit
- rcall delayOneSec
- rjmp test_tfs
- ;-------------
- fastHalf: ;test halfbit time at its fastest ie. all machine code
- rcall stopTim0u ;need this?
- rcall clrTCNT0
- LDI r16,0b0000_0011 ; 2=/8 3=/64 4 = /256 5 /1024 SET TIMER PRESCALER TO , 03 is /64
- OUT TCCR0B,r16 ;now timer 0 started
- rcall halfBitTime ;smallest delay, time it
- rcall stopTim0u
- in r16,TCNT0 ;get timer result, should be about 104
- rcall d16 ;show what's in r16
- ret
- ; rcall delayOneSec ;wait a bit then ..
- ;rjmp fastHalf
- ;-----------------
- BfastHalf: ;same as above but clrTCNT0 done by forth
- ; rcall clrTCNT0 ;
- ; LDI r16,0b0000_0011 ; 2=/8 3=/64 4 = /256 5 /1024 SET TIMER PRESCALER TO , 03 is /64
- ; OUT TCCR0B,r16 ;now timer 0 started
- ; rcall halfBitTime ;smallest delay, time it
- ; rcall stopTim0u
- in r16,TCNT0 ;get timer result, should be about 104
- rcall d16 ;show what's in r16
- ret
- ;---------------------working on PCINT3-----
- ;assume we have a square wave coming into PB3. First want machine code polling routine.
- pollPB3:
- in r16,DDRB
- andi r16,0b1111_0111 ;make Pin pb3 an input
- out DDRB,r16
- ldi r16,$ff
- out PORTB,r16
- readPB3:
- in r16,PINB
- rcall d16
- rcall delayOneSec
- rjmp pollPB3
- ;-------------------------------
- ;takout later. Having troubles with clrbit; need to trace it.
- clrbitcode2: ; (n16 n16 --) (bit_no, reg_no --) eg 0003 0038 clrbit clrs bit 3 of PORTB
- pushx
- mypop2 xh,xl ;ioadr now in x . Stck now ( mask_num --)
- rcall maskcode ;(mask --)
- mypopb ;mask now in r18
- com r18 ;make eg 00001000 into complement = 11110111
- ld r16,x ;get io reg contents, or RAM contents
- rcall d16
- and r16,r18 ;makes bit at mask-position a 0 in r16
- rcall d16
- st x, r16 ;send amended val back to RAM byte
- popx
- ret ;with one particular bit cleared in RAM/IO byte
- ;-------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement