I just started to learn Padauk microcontrollers and I did not find a pure assembler. I decided to write one. This is not a competitor of SDCC or other more advanced developent tools and programming languages but
sometimes less is more. I tried to keep it as simple as possible make it easy to learn. If you have some assembly programming background you will learn to use it a few minutes.
The syntax is very simple.
Keep in mind this is the first assembler I wrote, very experimental, not fully tested...
At this moment PFS154 is the only supported microcontroller. Maybe I will add PFS173 later. I don't plan to create assembler for OTP (One-Time Programmable) microcontrollers.
You can write the source code in any plain text editor. Save the file as "a.asm" at the same folder where pfs154.py located. The assembler is written in Python 3. You can download Python for free.
Open the pfs154.py file and click Run > Run Module or just hit F5.
The assembler will create a parsed.temp file (you can delete it) and an a.hex file. For Windows users if you don't want to download Python there is an PFS154.exe in downloads, you may run that in cmd.
You can download the a.hex to PFS154 microcontroller with your free-pdk programmer.
easypdkprog -n PFS154 write a.hex
I tried to stick to the syntax you can find in PFS154 data sheet as much as possible. You should learn only a very few extra syntax. The assembler is case insensitive, lowercase and uppercase letters are threated equivalent.
Segments
There are 2 segments, .var for variables and .rom for code. .var is optional but if exists it should be before .rom
.var
; put variables here
.rom
; put code here
Declare variables
Padauk use M keyword for SRAM where we store our variables. But there is a very similar space called IO. This is for Special Function Registers (SFR). In my assembler we have to specify with M or IO prefix where we store our variable. First comes the varible name then the address with M or IO prefix, a 2 digit hex number for address and 'h' in the end represents its hex number. The good news you don't have to declare the SFR-s, I already declared them in program. You can find the list of already declared SFRs in pfs154.py source code after "var =" line.
.var
myvar M2Ah
clkmd IO03h
Bit declaration
You can declare bits also. Flag bits are already declared like so
.var
mybit M14h.5
Z IO00h.0 ; Flag register Zero bit
C io00h.1 ; Flag register Carry bit
If you have a declared varible like above the myvar, you can access any bit using the myvar.n syntax without declaring the bit. Port registers are already declared, PA, PB... If you want to access a bit for example PA.0 you can use it in the code - no need to declare it.
Code syntax
Labels must end with colon. (label:)
Immediate (literal, constant) values MUST start with #.
After .orgxxxh directive the code will start at the provided address. Only 3 digit hex number accepted here. Interrupt starts at 10h address so it is usefull here.
After call and goto you may use label or direct address. For calibration we have to call 0x7ed to return the calibration value. You can use the call $xxxh syntax, call $7edh in this case for IHRC calibration.
Start-up code
.rom
wdreset
mov a,#9ch ; setup clkmd, IHRC/64, disable watchdog
mov clkmd,a
call $7edh ; clock calibration
mov ihrcr,a
call $7eeh ; bandgap tuning
mov bgtr,a
mov a,#40h ; set stack pointer 0x40 = 64
mov sp,a
I do recommend always set up the Clock Mode (clkmd), do the IHRC calibration, bandgap tuning and set up the stack pointer in the beginning of your code.
LED blinker
1sec on/off state will alter.
.var
t1 M00h
t2 M01h
t3 M02h
.rom
wdreset
mov a,#34h
mov clkmd,a
call $7edh
mov ihrcr,a
call $7eeh
mov bgtr,a
mov a,#40h ;0x40 = 64
mov sp,a
set1 pac.0
clear t1
mov a,#40
mov t2,a
mov a,#1
lab1:
xor pa,a
call wait1s
goto lab1
wait1s:
pushaf
clear t1
clear t2
mov a,#24
mov t3,a
w1:
nop
nop
dzsn t1
goto w1
dzsn t2
goto w1
dzsn t3
goto w1
popaf
ret
Advanced LED blinker :D
In this example you can see how to use T16 timer and interrupt. 264ms on/off state will alter.
.var
t1 M20h
t2 M21h
.rom
wdreset
goto main
.org010h ; interrupt
pushaf
mov a,#1
xor pa,a
set0 intrq.2
popaf
reti
main:
mov a,#34h
mov clkmd,a
call $7edh
mov ihrcr,a
call $7eeh
mov bgtr,a
mov a,#40h ; 0x40 = 64
mov sp,a
set1 pac.0
clear t1
clear t2
stt16 t1
set1 integs.4 ; falling edge
mov a, #9fh ; IHRC, div=64, interrupt change on 15th bit
mov t16m, a
set0 intrq.2 ; clear T16 irq flag
set1 inten.2 ; enable T16 interrupt
engint
loop:
nop
nop
nop
goto loop