CC = gcc
-CFLAGS = -ggdb -O2
+CFLAGS = -ggdb -O2 -Wall
YACC = bison -y -d
LEX = flex -i
LEXLIB =
-xa_asm: xa_main.o xa_asm.tab.o xa_asm.lex.o xa_dasm.o
- $(CC) -o xa_asm xa_main.o xa_asm.tab.o xa_asm.lex.o xa_dasm.o $(LEXLIB)
- #strip xa_asm
+xa_rasm: xa_main.o xa_rasm.tab.o xa_rasm.lex.o
+ $(CC) -o xa_rasm xa_main.o xa_rasm.tab.o xa_rasm.lex.o $(LEXLIB)
+ #strip xa_rasm
-xa_asm.lex.o: xa_asm.lex.c xa_asm.tab.h xa_main.h
- $(CC) $(CFLAGS) -c xa_asm.lex.c
+xa_rasm.lex.o: xa_rasm.lex.c xa_rasm.tab.h xa_main.h
+ $(CC) $(CFLAGS) -c xa_rasm.lex.c
-xa_asm.tab.o: xa_asm.tab.c xa_asm.tab.h xa_main.h
- $(CC) $(CFLAGS) -c xa_asm.tab.c
+xa_rasm.tab.o: xa_rasm.tab.c xa_rasm.tab.h xa_main.h
+ $(CC) $(CFLAGS) -c xa_rasm.tab.c
xa_main.o: xa_main.c xa_main.h
$(CC) $(CFLAGS) -Wall -c xa_main.c
-xa_dasm.o: xa_dasm.c
- $(CC) $(CFLAGS) -Wall -c xa_dasm.c
+xa_rasm.tab.c xa_rasm.tab.h: xa_rasm.y
+ $(YACC) xa_rasm.y
+ mv y.tab.c xa_rasm.tab.c
+ mv y.tab.h xa_rasm.tab.h
-xa_asm.tab.c xa_asm.tab.h: xa_asm.y
- $(YACC) xa_asm.y
- mv y.tab.c xa_asm.tab.c
- mv y.tab.h xa_asm.tab.h
+xa_rasm.lex.c: xa_rasm.l
+ $(LEX) xa_rasm.l
+ mv lex.yy.c xa_rasm.lex.c
-xa_asm.lex.c: xa_asm.l
- $(LEX) xa_asm.l
- mv lex.yy.c xa_asm.lex.c
-
-all: touch xa_asm
-
-touch:
- touch xa_asm.y xa_asm.l xa_dasm.c
+all: xa_rasm
clean:
rm -f *.tab.c *.tab.h *.lex.c *.o *.bak y.output *.hex *.lst *.obj
- rm -f xa_asm core *~
+ rm -f xa_rasm core *~
+++ /dev/null
-
-;this is a comment
-
- .equ var, 40
- .bit my_bit, var.5 ;this is another comment
-
- add r5, r1
- add r4l, r2h ;this is the third comment
- add r14, r2
-
- add [r5], r11
- add [r4], r1h
-
- add r2, [r0]
- add r4l, [r5]
-
- add r3, [r1+54]
- add r6h, [r5+31]
-
- add [r7+3], r2l
- add [r6+2], r5
-
- add r4, [r2+5405]
- add r3h, [r5+-31321]
-
- add [r1+1032], r3l
- add [r2+-1232], r7
-
- add r1, [r6+]
- add r3h, [r2+]
-
- add [r5+], r2
- add [r1+], r7l
-
- add 341, r3
- add 345, r1l
-
- add.w r6, 31
- add.b r5h, 1029
-
- add r3l, #54
- add r0, #12411
-
- add.w [r7], #4223
- add.w [r1], #41122
-
- add.b [r1+], #45
- add.b [r6+], #-10
-
- add.b [r2+42], #41
- add.w [r1+89], #3112
-
- add.b [r7+32321], #12
- add.w [r3+8761], #5891
-
- add.b 1231, #31
- add.w 156, #9861
-
- add r0, r1
- mov [r4+4], r6
-loop: mov r2, r1
- asr r1, #3
- mov r1l, #9
- mov [r1+4], r2
- jmp loop
- bov loop
-
- addc r15, r4
- addc r11, r10
- addc.b [r7+4], #-30
- addc.b [r3+], #21
- addc.w [r7+4], #-30
- addc.w [r3+], #321
-
- adds r3, #4
- adds.w [r1], #6
- adds.w [r0+], #-3
- adds.w [r5+4], #2
- adds.w [r2+-500], #1
- adds.w var, #1
-
- adds r3h, #4
- adds.b [r1], #6
- adds.b [r0+], #-3
-t1: adds.b [r5+4], #2
- adds.b [r2+-500], #1
- adds.b var, #1
-
-t2: and [r5+3287], r1l
- and.w var, #2011
-
- anl c, 43.1
- anl c, /my_bit
-
- asl r3, r1l
- asl r11, r5h
-t65: asl.d r4, r1h
- asl.w r0, r4l
- asl.b r4h, r3l
- asl r0, r4l
-
-
- asl.b r1l, #6
- asl.b r3h, #11
- asl.w r1, #3
- asl.w r4, #7
- asl r1l, #6
- asl r3h, #11
- asl r1, #3
- asl r4, #7
- asl.d r2, #9
- asl.d r2, #21
-
- asr r4l, r1h
- asr r4, r1h
- asr.w r0, r4l
- asr.w r4, #7
- asr.d r1, #9
- asr.d r6, #14
- asr.d r5, #27
-
- bcc loop
-t7: bcs t65
- beq t7
- bg t65
- bge t1
- bgt t1
- bkpt
- bl t7
- ble loop
- blt loop
- bmi t2
- bne t1
- bnv t65
- bov t2
- bpl t2
- br loop
- call t2
- call [r1]
-
-
+++ /dev/null
-;local lable test... labels consisting of one of more numbers
-;with a dollar sign on the end are considered to be local
-;labels and are unique within a section of code following
-;a normal non-local label
-
-
- .equ var, 40
- .bit my_bit, var.5 ;this is another comment
-
-begin:
- add r5, r1
- add r4l, r2h ;this is the third comment
- add r14, r2
-
-00001$: add [r5], r11
- add [r4], r1h
-
- jmp 00001$
- add r2, [r0]
- add r0, r1
- mov [r4+4], r6
- bkpt
-00002$: mov r2, r1
- asr r1, #3
- mov r1l, #9
- bne another_function
- mov [r1+4], r2
- jmp 00002$
- bkpt
-
-
-another_function:
- add r4l, [r5]
- add.b [r6+], #-10
-00001$: add.b [r7+32321], #12
- add.b 1231, #31
- beq 00001$
- djnz r2, 00001$
- jmp begin
-
+++ /dev/null
-
-;$include xa-g3.equ ;will implement included later on
-
-
-; Include file for XA-G3 SFR Definitions
-; Philips Semiconductors. Revision 1.8, 1/21/97
-; $nolist ;will implement this later on
-
-; Register equates.
-
-acc reg R4L ; for translated 80C51 code
-dpl reg R6L ; for translated 80C51 code
-dph reg R6H ; for translated 80C51 code
-sp reg R7 ; for translated 80C51 code
-
-
-; SFR byte and bit definitions.
-
-bcr sfr 46ah
-btrh sfr 469h
-btrl sfr 468h
-cs sfr 443h
-ds sfr 441h
-es sfr 442h
-
-ieh sfr 427h
-eri0 bit ieh.0
-eti0 bit ieh.1
-eri1 bit ieh.2
-eti1 bit ieh.3
-
-iel sfr 426h
-ex0 bit iel.0
-et0 bit iel.1
-ex1 bit iel.2
-et1 bit iel.3
-et2 bit iel.4
-ea bit iel.7
-
-ipa0 sfr 4a0h
-ipa1 sfr 4a1h
-ipa2 sfr 4a2h
-ipa4 sfr 4a4h
-ipa5 sfr 4a5h
-
-p0 sfr 430h
-p1 sfr 431h
-p2 sfr 432h
-p3 sfr 433h
-p0cfga sfr 470h
-p1cfga sfr 471h
-p2cfga sfr 472h
-p3cfga sfr 473h
-p0cfgb sfr 4f0h
-p1cfgb sfr 4f1h
-p2cfgb sfr 4f2h
-p3cfgb sfr 4f3h
-
-pcon sfr 404h
-idl bit pcon.0
-pd bit pcon.1
-
-pswh sfr 401h
-im0 bit pswh.0
-im1 bit pswh.1
-im2 bit pswh.2
-im3 bit pswh.3
-rs0 bit pswh.4
-rs1 bit pswh.5
-tm bit pswh.6
-sm bit pswh.7
-
-pswl sfr 400h
-z bit pswl.0
-n bit pswl.1
-v bit pswl.2
-ac bit pswl.6
-cy bit pswl.7
-
-psw51 sfr 402h
-
-rth0 sfr 455h
-rth1 sfr 457h
-rtl0 sfr 454h
-rtl1 sfr 456h
-
-s0con sfr 420h
-ri_0 bit s0con.0
-ti_0 bit s0con.1
-rb8_0 bit s0con.2
-tb8_0 bit s0con.3
-ren_0 bit s0con.4
-sm2_0 bit s0con.5
-sm1_0 bit s0con.6
-sm0_0 bit s0con.7
-scon sfr 420h ; duplicate label for translated 80C51 code.
-ri bit scon.0 ; duplicate label for translated 80C51 code.
-ti bit scon.1 ; duplicate label for translated 80C51 code.
-rb8 bit s0con.2 ; duplicate label for translated 80C51 code.
-tb8 bit s0con.3 ; duplicate label for translated 80C51 code.
-ren bit s0con.4 ; duplicate label for translated 80C51 code.
-sm2 bit s0con.5 ; duplicate label for translated 80C51 code.
-sm1 bit s0con.6 ; duplicate label for translated 80C51 code.
-sm0 bit s0con.7 ; duplicate label for translated 80C51 code.
-
-s0stat sfr 421h
-stint0 bit s0stat.0
-oe0 bit s0stat.1
-br0 bit s0stat.2
-fe0 bit s0stat.3
-
-s0buf sfr 460h
-sbuf sfr 460h ; duplicate label for translated 80C51 code.
-s0addr sfr 461h
-s0aden sfr 462h
-
-s1con sfr 424h
-ri_1 bit s1con.0
-ti_1 bit s1con.1
-rb8_1 bit s1con.2
-tb8_1 bit s1con.3
-ren_1 bit s1con.4
-sm2_1 bit s1con.5
-sm1_1 bit s1con.6
-sm0_1 bit s1con.7
-
-s1stat sfr 425h
-stint1 bit s1stat.0
-oe1 bit s1stat.1
-br1 bit s1stat.2
-fe1 bit s1stat.3
-
-s1buf sfr 464h
-s1addr sfr 465h
-s1aden sfr 466h
-
-scr sfr 440h
-
-ssel sfr 403h
-r0seg bit ssel.0
-r1seg bit ssel.1
-r2seg bit ssel.2
-r3seg bit ssel.3
-r4seg bit ssel.4
-r5seg bit ssel.5
-r6seg bit ssel.6
-eswen bit ssel.7
-
-swe sfr 47ah
-swr sfr 42ah
-swr1 bit swr.0
-swr2 bit swr.1
-swr3 bit swr.2
-swr4 bit swr.3
-swr5 bit swr.4
-swr6 bit swr.5
-swr7 bit swr.6
-
-swe1 equ 00000001q ; bit masks for software interrupt enables.
-swe2 equ 00000010q
-swe3 equ 00000100q
-swe4 equ 00001000q
-swe5 equ 00010000q
-swe6 equ 00100000q
-swe7 equ 01000000q
-
-t2con sfr 418h
-cprl2 bit t2con.0
-ct2 bit t2con.1
-tr2 bit t2con.2
-exen2 bit t2con.3
-tclk0 bit t2con.4
-rclk0 bit t2con.5
-tclk bit t2con.4 ; duplicate label for translated 80C51 code.
-rclk bit t2con.5 ; duplicate label for translated 80C51 code.
-exf2 bit t2con.6
-tf2 bit t2con.7
-
-t2mod sfr 419h
-dcen bit t2mod.0
-t2oe bit t2mod.1
-t2rd bit t2mod.2
-tclk1 bit t2mod.4
-rclk1 bit t2mod.5
-
-th2 sfr 459h
-tl2 sfr 458h
-t2caph sfr 45bh
-t2capl sfr 45ah
-
-tcon sfr 410h
-it0 bit tcon.0
-ie0 bit tcon.1
-it1 bit tcon.2
-ie1 bit tcon.3
-tr0 bit tcon.4
-tf0 bit tcon.5
-tr1 bit tcon.6
-tf1 bit tcon.7
-
-th0 sfr 451h
-th1 sfr 453h
-tl0 sfr 450h
-tl1 sfr 452h
-tmod sfr 45ch
-tstat sfr 411h
-t0oe bit tstat.0
-t0rd bit tstat.1
-t1oe bit tstat.2
-t1rd bit tstat.3
-
-wdcon sfr 41fh
-wdtof bit wdcon.1
-wdrun bit wdcon.2
-pre0 bit wdcon.5
-pre1 bit wdcon.6
-pre2 bit wdcon.7
-
-wdl sfr 45fh
-wfeed1 sfr 45dh
-wfeed2 sfr 45eh
-
-
-; Port pin name definitions.
-
-a4d0 bit P0.0
-a5d1 bit P0.1
-a6d2 bit P0.2
-a7d3 bit P0.3
-a8d4 bit P0.4
-a9d5 bit P0.5
-a10d6 bit P0.6
-a11d7 bit P0.7
-
-a0 bit P1.0
-wrh bit P1.0
-a1 bit P1.1
-a2 bit P1.2
-a3 bit P1.3
-rxd1 bit P1.4
-txd1 bit P1.5
-t2 bit P1.6
-t2ex bit P1.7
-
-a12d8 bit P2.0
-a13d9 bit P2.1
-a14d10 bit P2.2
-a15d11 bit P2.3
-a16d12 bit P2.4
-a17d13 bit P2.5
-a18d14 bit P2.6
-a19d15 bit P2.7
-
-rxd0 bit P3.0
-txd0 bit P3.1
-int0 bit P3.2
-int1 bit P3.3
-t0 bit P3.4
-t1 bit P3.5
-busw bit P3.5
-wrl bit P3.6
-rd bit P3.7
-
-; End of XA-G3 SFR definitions.
-;$list ;handle this later on
-
-
-
-
-trap_delay equ 0
-trap_cout equ 1
-
- org $8040 ;paulmon2 will jump here on trap #0
- jmp syscall_sleep
- org $8044 ;paulmon2 will jump here on trap #1
- jmp syscall_cout
-
- org $8084 ;paulmon2 will jump here on timer0 interrupt
- jmp timer0
-
- org $80A0 ;paulmon2 will jump here on uart0 rx interrupt
- jmp uart0_recv
- org $80A4 ;paulmon2 will jump here on uart0 tx interrupt
- jmp uart0_xmit
- org $80A8 ;paulmon2 will jump here on uart1 rx interrupt
- jmp uart1_recv
- org $80AC ;paulmon2 will jump here on uart1 tx interrupt
- jmp uart1_xmit
-
- org $8100 ;paulmon2 will jump here on software int1
- jmp context_switch
- org $8104 ;paulmon2 will jump here on software int2
- jmp do_events
-
- org $8120
- jmp poweron
-
-request_do_events bit swr2
-request_context_switch bit swr1
-
-max_num_ticks equ 7 ;max time a process can run if other
- ;processes are waiting in the run queue
-
-
-;this memory allocation should be done with "ds" directives to
-;save space, but for now it's done with "equ" with lots of gaps,
-;so that things will stay put and aligned on 16 byte boundries
-;where they can be easily viewed with the paulmon2 hex dump. When
-;the kernel code is more mature this will have to be changed.
-
-sys_stack equ $FB00
-
-rx0_buf_head equ $FB00 ;2 bytes
-rx0_buf_tail equ $FB02 ;2 bytes
-rx0_buf_size equ $20
-rx0_buf equ $FB10 ;rx0_buf_size bytes
-
-rx1_buf_head equ $FB40 ;2 bytes
-rx1_buf_tail equ $FB42 ;2 bytes
-rx1_buf_size equ $20
-rx1_buf equ $FB50 ;rx1_buf_size bytes
-
-tx0_buf_head equ $FB80 ;2 bytes
-tx0_buf_tail equ $FB82 ;2 bytes
-tx0_buf_size equ $20
-tx0_buf_threshold equ 9
-tx0_buf equ $FB90 ;tx0_buf_size bytes
-
-tx1_buf_head equ $FBC0 ;2 bytes
-tx1_buf_tail equ $FBC2 ;2 bytes
-tx1_buf_size equ $20
-tx1_buf_threshold equ 9
-tx1_buf equ $FBD0 ;tx1_buf_size bytes
-
-
-current_proc equ $FEF0 ;2 bytes, ptr to proc_table entry of
- ;currently running process, 0 if none
-run_queue equ $FEF2 ;2 bytes, pointer to a linked list
- ;of processes waiting to run
-sleep_queue equ $FEF4 ;2 bytes, pointer to a linked list
- ;of sleeping processes
-time_running equ $FEF6 ;1 byte, number of ticks that the
- ;current process has run.
-event_queue equ $FCF0 ;2 bytes, pointer to a linked list
- ;of pending events (event_table)
-
-max_num_proc equ 14
-proc_table equ $FE00 ;(max_num_proc*pt_entry_size) bytes
-pt_entry_size equ 16 ;16 bytes per table entry
-pt_usp equ 0 ;2 bytes, User Stack Pointer
-pt_q_next equ 2 ;2 bytes, ptr to next in queue
-pt_q_prev equ 4 ;2 bytes, ptr to prev in queue (+pt_q_next)
-pt_wait equ 6 ;2 bytes, what are we waiting for?
-pt_wakeup equ 8 ;2 bytes, where do we go on wakeup?
-pt_prog_addr equ 10 ;2 bytes, location of program header
-pt_prog_cs equ 12 ;1 byte, code segment of program header
-pt_priority equ 13 ;1 byte, execution priority
-pt_pid equ 14 ;1 byte, id num for this process
-
- ;need to define a program header, which will include various
- ;info about the program, including the req'd stack space, max
- ;expect memory to malloc, range of directly addressed memory
- ;(which must be saved during a context switch), max number of
- ;open file descriptors reqd, etc.
-
-max_num_event equ 15 ;(max_num_proc*2)
-event_table equ $FC00 ;(max_num_event*evt_entry_size)
-evt_entry_size equ 16 ;8 bytes per event entry
-evt_ticks equ 0 ;# of ticks until event (delta from prev)
-evt_next equ 2 ;pointer to next event in list
-evt_function equ 4 ;place to call (0 if evt slot unused)
-evt_arg1 equ 6 ;optional argument
-
-;the file descriptors will be allocated before the stack in the
-;block of memory which is allocated when the process is created.
-;each individual process can specify the max number of file
-;descriptors that it will require
-
-file_desc_table equ $FE80 ;128 bytes
-fd_entry_size equ 7 ;7 bytes per table entry
-fd_offset equ 0 ;4 bytes, offset in file
-fd_flags equ 4 ;1 byte, read/write/append
-fd_routines equ 5 ;2 bytes, ptr to i/o routines
-
-
-;single character debug symbols:
-; space context switcher is idle
-; * contect switcher entered
-; # timer interrupt (normal)
-; % timer interrupt requested context switch
-; ! timer interrupt requested event service
-; @ entered event service interrupt routine
-; ^ event service function called
-; ~ leaving event service interrupt routine
-
-;this timer interrupt routine is responsible for monitoring the
-;time that the current process has been running and adjusting the
-;process priorities accordingly. It also checks if any events
-;in the event queue need to be processed. This code runs at a
-;high cpu priority and it runs often, so it should get done as
-;quickly as possible... if anything lengthy might need to be done,
-;a software interrupt (low priority) should be set, so it can be
-;done later on without blocking other important interrupts, such
-;as low-level i/o.
-
-timer0:
- push r0, r1, r2, r3, r4, r5, r6
- ;other stuff can be added here, such as maintaining a
- ;system clock...
- ;mov r4l, #'#'
-check_events:
- mov r0, #event_queue
- clr ea
- mov r1, [r0]
- beq ckevt_end ;no events if queue is empty
- mov r2, [r1+evt_ticks]
- beq ckevt_do_em
- ;if we get here, there are events pending but it's not
- ;time to do any of them yet, so we'll just decrement the
- ;ticks of the first one, which will decrement the effective
- ;time for all of them since they use a delta-time between
- ;each entry in the linked list
- adds.w [r1+evt_ticks], #-1
- br ckevt_end
-ckevt_do_em:
- ;if we get here, there is at least one event which needs
- ;to be serviced... but we won't do that here, just set the
- ;software interrupt so it can be handled by "do_event"
- ;setb request_do_events
- ;mov r4l, #'!'
- ;call cout
- ;call do_events ;not nice, but sw int priority not working
- setb request_do_events
-ckevt_end:
- setb ea
- nop
-schedule:
- mov r0, #current_proc
- clr ea
- mov r1, [r0]
- beq sch_end ;don't bother if no process is running
- sub.b [r1+pt_priority], #1 ;decrease priority by one
- bcc sch_priority_ok
- movs.b [r1+pt_priority], #0 ;but don't go less than zero
-sch_priority_ok:
- mov r0, #time_running
- mov r3l, [r0]
- adds r3l, #1 ;increment time_running
- mov [r0], r3l
- cmp r3l, #max_num_ticks
- bl sch_end
- ;if we get here, the currently running process is has been
- ;using the cpu for at least the max number ticks, so it's
- ;time to force it to take a rest and let someone else have
- ;a chance.
- mov r0, #run_queue
- mov r1, [r0]
- beq sch_end ;don't preempt if nothing in run queue
- ;mov r4l, #'%'
- setb request_context_switch ;make something else run
-sch_end:
- setb ea
- ;cmp r4l, #'!'
- ;beq t0_skip_print
- ;call cout
- nop
-t0_skip_print:
- pop r0, r1, r2, r3, r4, r5, r6
- reti
-
-
- ;this routine actually calls the event handlers for all
- ;events which are supposed to happen NOW. The main timer
- ;routine must decrement the time of the events and arrange
- ;for this code to be run when any events are supposed to
- ;happen. The event handler gets the address of the event
- ;in r1.
-do_events:
- push r0, r1, r2, r3, r4, r5, r6
-do_events_begin:
- ;mov r4l, #'@'
- ;call cout
-doevt_loop:
- mov r0, #event_queue
- mov r1, [r0]
- beq doevt_end ;no events to do if queue is empty
- mov r2, [r1+evt_ticks]
- bne doevt_end ;done if event is in the future
- mov r2, [r1+evt_next]
- mov [r0], r2 ;remove event from queue
- mov r2, [r1+evt_function]
- movs.w [r1+evt_function], #0
- ;mov r4l, #'^'
- ;call cout
- call [r2] ;call the event handler specified
- br doevt_loop
-doevt_end:
- ;mov r4l, #'~'
- ;call cout
- clr request_do_events
- pop r0, r1, r2, r3, r4, r5, r6
- reti
-
-
-
-;interrupt receive routine for uart #0
-uart0_recv:
- push r0, r1, r2, r5, r6
- clr ri_0
- mov r5l, s0buf
- mov r2, #rx0_buf
- mov r0, #rx0_buf_head
- mov r6, #rx0_buf_tail
- mov r1, [r0]
- adds r1, #1
- cjne r1, #rx0_buf+rx0_buf_size, uart_recv_check2
- mov r1, #rx0_buf
- br uart_recv_check2
-;interrupt receive routine for uart #1
-uart1_recv:
- push r0, r1, r2, r5, r6
- clr ri_1
- mov r5l, s1buf
- mov r2, #rx1_buf
- mov r0, #rx1_buf_head
- mov r6, #rx1_buf_tail
- mov r1, [r0]
- adds r1, #1
- cjne r1, #rx1_buf+rx1_buf_size, uart_recv_check2
- mov r1, #rx1_buf
-;this remaining code is shared by both uart receive routines
-uart_recv_check2:
- cmp r1, [r6]
- bne uart_recv_ok
- ;if we get here, the buffer is full, discard data
- call wakeup_intr_io
- pop r0, r1, r2, r5, r6
- reti
-uart_recv_ok:
- mov.b [r1], r5l ;store byte into buffer
- mov [r0], r1 ;update buffer pointer
- ;perhaps there should be a way for us to know how much data a
- ;sleeping process wants to extract from the buffer, so we can
- ;avoid waking it up until there is at least that much data.
- call wakeup_intr_io
- pop r0, r1, r2, r5, r6
- reti
-
-;interrupt transmit routine for uart #0
-uart0_xmit:
- push r0, r1, r2, r5, r6
- clr ti_0
- mov r0, #tx0_buf_tail
- mov r2, #tx0_buf_head
- mov r1, [r0]
- cmp r1, [r2]
- beq uart_no_xmit
- adds r1, #1
- cjne r1, #tx0_buf+tx0_buf_size, uart0_xmit2
- mov r1, #tx0_buf
-uart0_xmit2:
- mov.b s0buf, [r1]
- mov [r0], r1
- ;now figure out if we want to wake up processes which are
- ;waiting to put more data into this buffer
- mov r1, [r2]
- sub r1, [r0]
- bcc uart0_xmit3
- add r1, #tx0_buf_size
-uart0_xmit3:
- cmp r1, #(tx0_buf_threshold)
- bcc uart0_xmit_end ;don't wake proc unless over threshold
- mov r2, #tx0_buf
- call wakeup_intr_io
-uart0_xmit_end:
- pop r0, r1, r2, r5, r6
- reti
-;interrupt transmit routine for uart #1
-uart1_xmit:
- push r0, r1, r2, r5, r6
- clr ti_1
- mov r0, #tx1_buf_tail
- mov r2, #tx1_buf_head
- mov r1, [r0]
- cmp r1, [r2]
- beq uart_no_xmit
- adds r1, #1
- cjne r1, #tx1_buf+tx1_buf_size, uart1_xmit2
- mov r1, #tx1_buf
-uart1_xmit2:
- mov.b s1buf, [r1]
- mov [r0], r1
- ;now figure out if we want to wake up processes which are
- ;waiting to put more data into this buffer
- mov r1, [r2]
- sub r1, [r0]
- bcc uart1_xmit3
- add r1, #tx1_buf_size
-uart1_xmit3:
- cmp r1, #tx1_buf_threshold
- bcc uart1_xmit_end ;don't wake proc unless over threshold
- mov r2, #tx1_buf
- call wakeup_intr_io
-uart1_xmit_end:
- pop r0, r1, r2, r5, r6
- reti
-
-;this is shared by both transmit interrupt routines
-uart_no_xmit:
- ;if we got here, there is no data waiting to transmit
- ;load the _head pointer with 0, so a routine which loads
- ;data into the buffer will know to set the ti bit.
- movs.w [r2], #0
- pop r0, r1, r2, r5, r6
- reti
-
-
-;This routine wakes up any sleeping processes that are waiting
-;for i/o in the buffer pointed to by r2. Interrupt routines
-;should call here after doing i/o one their buffers, so that
-;any processes which are waiting for that i/o will be awakened.
-
-wakeup_intr_io:
- mov r0, #sleep_queue
- mov r1, [r0]
- beq wkintio_empty ;sleep_queue is empty
- clr ea ;disable interrupts while we look at the queue
-wkintio_loop:
- cmp [r1+pt_wait], r2
- beq wkintio_wakeup ;wake proc if waiting for i/o on this buffer
- mov r1, [r1+pt_q_next]
- bne wkintio_loop
- setb ea ;ok for other interrupts now
-wkintio_empty:
- ret
-wkintio_wakeup:
- ;if we get here, this sleeping processes was waiting for
- ;i/o on the buffer pointed to by r2, so let's wake it up.
- ;d_que_proc: (remove from sleep queue)
- mov r6, [r1+pt_q_next]
- push r6 ;save ptr to next in sleep queue
- mov r5, [r1+pt_q_prev]
- mov [r5], r6
- mov [r6+pt_q_prev], r5
- ;en_que_proc: (add to run queue)
- mov r0, #run_queue
- mov [r1+pt_q_prev], r0
- mov r5, [r0]
- mov [r1+pt_q_next], r5
- lea r6, r1+pt_q_next
- mov [r5+pt_q_prev], r6
- mov [r0], r1
- adds.b [r1+pt_priority], #5 ;give it a bit of priority boost...
- ;need to check here for overrange on user priority
- setb request_context_switch ;get it running asap.
- ;continue looking for processes waiting on this i/o buffer,
- ;because there may be more than one, and we need to get them
- ;all into the run queue so that the context switcher can choose
- ;the one with the highest priority.
- pop r1
- cmp r1, #0
- bne wkintio_loop
- setb ea
- ret
-
-
-
-
-
-
-
-;**************************************************************
-
-
-
-
-
-
-;The context switcher is responsible for figuring out which process
-;is supposed to run next (looks at pt_priority) and if a context
-;change is required this is where it will happen. If any
-;interrupt driven part of the kernel wants to make a particular
-;process run, it must change the priority for that process and
-;then set the software interrupt to run the context switcher later.
-
-;For system calls that want to make their calling process sleep,
-;they should jump to the ksleep routine, which will jump to
-;"ctsw_begin" to allow something else to run.
-
-;Note: the context switcher doesn't enforce preemptive multitasking...
-;a timer routine must count how long the currently running process
-;has be running since a context switch ("time_running" variable)
-;and if it's being a hog the timer routine that detects it must
-;lower the priority and set the software interrupt to cause this
-;context switcher to make a different process run. The context
-;switcher also depends on interrupt routines to change the
-;"pt_priority" field of each process table entry, all the context
-;switcher does is pick the process with highest priority. The
-;currently running process is always switched out if there is
-;something in the run queue, even if the item in the run queue
-;has a lower priority.
-
-
-context_switch:
- pushu r0, r1, r2, r3, r4, r5, r6 ;save registers
- pop r2, r3, r4 ;get pc and psw
- pushu r2, r3, r4 ;save them on user stack
- pushu.b ds
- pushu.b es
- pushu.b ssel
-
-
-ctsw_begin:
- ;mov r4l, #'*'
- ;call cout
-ctsw_retry:
- ;find the process on the run queue with highest priority
- mov r0, #run_queue
- mov r1, [r0]
- beq ctsw_queue_empty ;run_queue is empty
- movs r2, #0 ;r2 is proc w/ highest priority
- mov r3l, #0 ;r3l is highest priority we've seen
- clr ea ;disable interrupts while we look at the
- ;run queue, since interrupt routines will be
- ;changing priorities to influence which process
- ;should be run next
-ctsw_loop:
- cmp [r1+pt_priority], r3l
- bcs ctsw_skip
- ;if we get here, this process is the highest
- ;priority so far, so forget about any other
- mov r3l, [r1+pt_priority]
- mov r2, r1
-ctsw_skip:
- mov r1, [r1+pt_q_next]
- bne ctsw_loop
- ;now r2 points to the process which should be running...
- ;check to see if "current_proc" is valid... if it is zero then
- ;nothing was running (a sys call probably put the process to
- ;sleep). If "current_proc" has a valid process pointer, then we
- ;need to save that process's context (apart from the pushed regs)
- ;and put that process back into the run queue
- mov r0, #current_proc
- mov r1, [r0]
- beq ctsw_switch
- call save_context
- movs.w [r1+pt_wakeup], #0 ;wants to go back to user mode
- mov r0, #run_queue
- call en_que_proc ;put back into run queue
-ctsw_switch:
- ;now it's time to switch to the new process that is about
- ;to start running.
- mov r1, r2
- call d_que_proc ;remove new proc from run queue
- call restore_context
- mov r0, #time_running
- movs.b [r0], #0 ;reset "time_running"
- mov r0, #current_proc
- mov [r0], r1 ;set "current_proc" to new process
- ;we may need to return to executing the process in user mode,
- ;or we may need to jump to a location in the kernel (to continue
- ;a system call). If pt_wakup for this process is not zero, then
- ;some kernel routine caused this process to sleep or be preempted
- ;and wants to do more work before finally returning to the user
- ;mode and running the program again. Usually this is due to a
- ;system call which needed to put the process to sleep while
- ;waiting for I/O.
- mov r6, [r1+pt_wakeup]
- setb ea
- beq ctsw_return
- movs.w [r1+pt_wakeup], #0 ;don't do this again unless set again
- jmp [r6]
-ctsw_return:
- clr request_context_switch
- popu.b ssel
- popu.b es
- popu.b ds
- popu r2, r3, r4
- push r2, r3, r4
- popu r0, r1, r2, r3, r4, r5, r6
- reti
-
-ctsw_queue_empty:
- ;if we get here, there was no process waiting in the run
- ;queue. However, the currently running process isn't
- ;normally in the run queue, so check if there was a process
- ;running... if so reset its time slice and let it continue
- mov r0, #current_proc
- mov r1, [r0]
- beq ctsw_idle ;idle if nothing was running
- mov r0, #time_running
- movs.b [r0], #0
- jmp ctsw_return
- ;if we get here, the run queue is empty and there in no
- ;process running now, so we just keep looping inside the
- ;context switcher until something appears in the run queue
-ctsw_idle:
- ;need to make a special user-mode idle process... someday
- ;that could put the processor into idle-mode to save power
- ;mov r4l, #' '
- ;call cout
- jmp ctsw_retry
-
-
-
-
-;This "ksleep" routine causes the current process to sleep, afterwhich
-;it jumps to the context switcher, which tries to pick something else to
-;run, if anything is ready. This code should only be called from
-;within the service code of system calls, which often times need to
-;make their calling process sleep. R3 should have a value to stuff
-;into "pt_wait" for the process. ksleep should be CALLed, because
-;it will arrange for the scheduler to return back to the kernel code
-;which called ksleep. The call to ksleep should be followed by a
-;single NOP, for jump alignment. Note, before calling ksleep some mechanism
-;to wake the sleeping process back up again must be in place... there
-;is nothing within ksleep which arranges for the process to become
-;awake again, though in the case of i/o the value in r3 should cause it
-;to wake up of the i/o interrupt routine checks for that value.
-
-ksleep:
- clr ea
- mov r0, #current_proc
- mov r1, [r0] ;get pointer to process
- ;cmp r1, #$FE10
- ;beq ksleep_die
- movs.w [r0], #0 ;no current process anymore
- nop
-ksleep_any:
- clr ea
- mov [r1+pt_wait], r3 ;record what we're waiting for
- pop r5, r6 ;get return address
- adds r6, #1 ;make sure return addr is word addr
- and r6, #$FFFE
- mov [r1+pt_wakeup], r6 ;set return addr when it wakes up
- adds.b [r1+pt_priority], #3 ;increase priority a bit
- ;need to check here for overrange on user priority
- mov r0, #sleep_queue
- call en_que_proc ;add it to the sleep queue
- setb ea
- call save_context
- ;cmp r1, #$FE10
- ;beq ksleep_die
- jmp ctsw_begin ;scheduler will pick a new
- ;process to run (or run idle loop)
-
-ksleep_die:
- jmp die
-
-
-syscall_sleep:
- ;all system calls should run at the same priority as the
- ;context switcher (level #1), but the code in paulmon2
- ;sets the trap priority to #8... need to change that.
- mov.b pswh, #10000001q
- pushu r0, r1, r2, r3, r4, r5, r6 ;save registers
- pop r4, r5, r6 ;get pc and psw
- pushu r4, r5, r6 ;save them on user stack
- pushu.b ds
- pushu.b es
- pushu.b ssel
- ;r0 is number of ticks to sleep, from caller
- mov r4, #wake_process
- mov r2, #current_proc
- mov r5, [r2] ;"wake_process" will need to know which proc
- call add_event
- mov r3, #0 ;no other routines will need to know it's sleeping
- call ksleep
- nop
- popu.b ssel
- popu.b es
- popu.b ds
- popu r2, r3, r4
- push r2, r3, r4
- popu r0, r1, r2, r3, r4, r5, r6
- reti
-
- ;do_events is supposed to call here when the process is supposed
- ;to wake up again... all we have to do it remove the process
- ;from the sleep queue, add it to the run queue, and set the
- ;software interrupt for the context switcher so it will select
- ;a new process to run, and it will likely be this one since we
- ;gave the priority a boost when it was put to sleep.
- nop
-wake_process:
- ;mov r4l, #'$'
- ;call cout
- ;r1 should point to event table entry created earlier
- clr ea
- mov r1, [r1+evt_arg1] ;now r1 points to process entry
- call d_que_proc ;remove it from the sleep queue
- mov r0, #run_queue
- call en_que_proc ;add it to the run queue
- setb ea
- ;should really test the priority of this waking process and
- ;the priority of the currently running one, and only do the
- ;context switch if the waking one has a higher priority
- setb request_context_switch
- ret
-
-
-
-
- ;transmit the character in r4l
-syscall_cout:
- mov.b pswh, #10000001q
- pushu r0, r1, r2, r3, r4, r5, r6 ;save registers
- pop r3, r5, r6 ;get pc and psw
- pushu r3, r5, r6 ;save them on user stack
- pushu.b ds
- pushu.b es
- pushu.b ssel
-sc_cout_begin:
- mov r0, #tx0_buf_head
- mov r2, #tx0_buf_tail
- clr ea
- mov r1, [r0]
- bne sc_cout2
- ;if we get here, the transmit buffer is empty and the interrupt
- ;routine cleared the ti bit so no more interrupts are expected
- setb ti_0 ;give the transmitter a kick-start
- mov r1, #tx0_buf
- mov [r0], r1 ;restore buffer pointers to useful values
- mov [r2], r1
-sc_cout2:
- adds r1, #1
- cjne r1, #tx0_buf+tx0_buf_size, sc_cout3
- mov r1, #tx0_buf
-sc_cout3:
- cmp r1, [r2]
- bne sc_cout4
- ;if we get here, the buffer is full, so let's just wait
- ;in a loop... eventually this routine will be replaced
- ;with "write" which will put the process to sleep and set
- ;the pt_wait so the context switcher will return here when
- ;there is space available. How do we save the variables
- ;associated with the system call?? Push them onto the
- ;user's stack for this process?
- setb ea
- mov r3, #tx0_buf
- pushu r4
- call ksleep
- nop
- popu r4
- br sc_cout_begin ;try again now that the intr i/o woke us up
-sc_cout4:
- mov.b [r1], r4l ;put data into buffer
- mov [r0], r1 ;update pointer
- setb ea
- popu.b ssel
- popu.b es
- popu.b ds
- popu r2, r3, r4
- push r2, r3, r4
- popu r0, r1, r2, r3, r4, r5, r6
- reti
-
-
-
-
-
-
-
-
- ;this function adds an event to the event queue. These
- ;parameters are required:
- ; r0 number of ticks until the event should occur
- ; r4 function to call when event happens (not zero!!)
- ; r5 optional argument
- ;the event list uses delta time between each entry, so that
- ;the timer interrupt will only have to deal with the front
- ;of the queue... but it makes adding an entry here much more
- ;difficult, but we only have to do this once whereas the
- ;timer will have to look at the queue however many times the
- ;evt_ticks value specifies.
-add_event:
- ;the first thing to do is find a empty place in the table
- ;to store this event
- mov r1, #event_table
- mov r2, #max_num_event
- clr ea
-aevt_find_slot:
- mov r3, [r1+evt_function]
- beq aevt_found_slot
- add r1, #evt_entry_size
- djnz r2, aevt_find_slot
- ;if we get here there were no slots available, which is a
- ;very bad thing...
- jmp kernel_panic
-aevt_found_slot:
- ;now that we've located the slot we'll use, let's dump the
- ;data into it before making a mistake and reusing one of the
- ;registers that are holding the input parameters
- mov [r1+evt_ticks], r0 ;store time value
- mov [r1+evt_function], r4 ;store function to be called
- mov [r1+evt_arg1], r5 ;store argument
- ;now we've got to add this event into the linked list in
- ;the correct time sequence position, and also subtract the
- ;sum of all the previous evt_ticks values from this one.
- mov r6, #event_queue
- mov r2, [r6]
- bne aevt_check_first
- ;if we get here, it's easy because the list is empty...
- mov [r6], r1
- movs.w [r1+evt_next], #0
- setb ea
- ret
-aevt_check_first:
- ;it may be the case that our new event is supposed to happen
- ;before the events that are already on the queue
- cmp r0, [r2+evt_ticks]
- bcc aevt_search
- mov [r6], r1
- mov [r1+evt_next], r2
-aevt_adjust:
- ;now that we've added an entry (at r1), we need to adjust the
- ;evt_ticks values stored in the entry that comes after it.
- mov r3, [r1+evt_next] ;r3 points to next event after ours
- mov r4, [r1+evt_ticks]
- sub [r3+evt_ticks], r4
- setb ea
- ret
-aevt_search:
- ;r4 is the adjusted value of ticks for our event as we progress
- ;through the linked list
- mov r4, [r1+evt_ticks]
-aevt_search_loop:
- sub r4, [r2+evt_ticks]
- mov r3, [r2+evt_next]
- beq aevt_add
- cmp r4, [r3+evt_ticks]
- bcs aevt_add
- mov r2, r3
- jmp aevt_search_loop
-aevt_add:
- ;r2 points to the event before the place where we will add
- ;and r3 points to the place after it in the list
- mov [r2+evt_next], r1
- mov [r1+evt_next], r3
- mov [r1+evt_ticks], r4
- bne aevt_adjust ;adjust rest of list if it exists
- setb ea
- ret
-
-
-
-
-save_context: ;process pointer in r1
- mov r0, usp
- mov [r1+pt_usp], r0 ;save user stack pointer
- ;save any directly addressed memory range
- ;assigned to this process
- ret
-
-restore_context: ;process pointer in r1
- mov r0, [r1+pt_usp]
- mov usp, r0 ;restore usp to value for new process
- ;copy contents of directly addresses memory
- ;back if necessary
- ret
-
-
-
-
-;This routine removes a process (at r1) from a process queue
-;(run/sleep). This might be better as an assembler macro, but
-;it's in a subroutine because of the difficulty of figuring out
-;how to correctly manipulate the pointers of a doubly-linked list
-d_que_proc:
- mov r6, [r1+pt_q_next] ;<-- should be macro (begin)
- mov r5, [r1+pt_q_prev]
- mov [r5], r6
- mov [r6+pt_q_prev], r5 ;<--- should be macro (end)
- ret
-
-;this routine takes a process (at r1) and adds it to a queue, where
-;the location of the head of the queue is in r0. This is more or
-;less the opposite of "d_que_proc" except that the new process is
-;always added to the head of the list.
-en_que_proc:
- mov [r1+pt_q_prev], r0 ;<-- should be macro (begin)
- mov r5, [r0]
- mov [r1+pt_q_next], r5
- lea r6, r1+pt_q_next
- mov [r5+pt_q_prev], r6
- mov [r0], r1 ;<--- should be macro (end)
- ret
-
-;pt_usp equ 0 ;2 bytes, User Stack Pointer
-;pt_q_next equ 2 ;2 bytes, ptr to next in queue
-;pt_q_prev equ 4 ;2 bytes, ptr to prev in queue (+pt_q_next)
-
-
-;this routine creates a new process, and returns a pointer to it
-;in r1. If the process can't be created, r1 is zero. Data about
-;the new process is required:
-; r4 = location of executable program
-; r5 = location for user stack (eventually malloc will do this)
-
-
-create_process:
- mov r1, #proc_table
- mov r2, #max_num_proc
-cproc_find_slot:
- mov r0, [r1+pt_usp]
- beq cproc_found_slot ;ok to use this process entry
- add r1, #pt_entry_size
- djnz r2, cproc_find_slot
- ;if we get here, there is no more room in the process
- ;table so we can't create a new process.
- movs r1, #0
- ret
-cproc_found_slot:
- push r4, r5
- ;first initialize the various kernel data required
- mov r0, #run_queue
- clr ea
- call en_que_proc ;add it to the run queue
- mov.b [r1+pt_priority], #100 ;start at priority 100
- movs.w [r1+pt_wait], #0
- movs.w [r1+pt_wakeup], #0
- ;next we need to set up the process's context
- pop r4, r5
- sub r5, #26 ;advance r5 to context storage area
- mov [r1+pt_usp], r5
- movs.w [r5+], #0 ;segment select is 0
- movs.w [r5+], #0 ;es is 0
- movs.w [r5+], #0 ;ds is 0
- movs.w [r5+], #0 ;psw is zero (user mode)
- movs.w [r5+], #0 ;run is page zero only (for now)
- mov [r5+], r4 ;set return addr to beginning
- ;could create initial values for the registers here...
- setb ea
- ret
-
-;user stack while in kernel mode:
-; byte
-; offset Variable
-; -2 r6
-; -4 r5
-; -6 r4
-; -8 r3
-; -10 r2
-; -12 r1
-; -14 r0
-; -16 program counter (lsw)
-; -18 program counter (msb)
-; -20 program status word
-; -22 ds
-; -24 es
-; -26 ssel <-- usp points here
-
-
-poweron:
- mov r6, #$F000
-clear_memory_loop:
- movs.w [r6+], #0
- cjne r6, #0, clear_memory_loop
- setb p1.6
- setb p1.7
-
- mov r7, #sys_stack ;set sys stack pointer
- clr ea
- ;initialize serial port buffers
- mov r0, #rx0_buf_head
- mov.w [r0], #rx0_buf
- mov r0, #rx0_buf_tail
- mov.w [r0], #rx0_buf
- mov r0, #tx0_buf_head
- movs.w [r0], #0
- mov r0, #tx0_buf_tail
- movs.w [r0], #0
- mov r0, #rx1_buf_head
- mov.w [r0], #rx1_buf
- mov r0, #rx1_buf_tail
- mov.w [r0], #rx1_buf
- mov r0, #tx1_buf_head
- movs.w [r0], #0
- mov r0, #tx1_buf_tail
- movs.w [r0], #0
- ;clear serial port flags
- clr ri_0
- clr ti_0
- clr ri_1
- clr ti_1
- ;initialize interrupts
- mov.b swe, #255 ;allow all software interrupts
- mov.b ipa0, #10010000q ;priority #9: timer0 interrupt
- mov.b ipa4, #10011001q ;priority #9: uart0 rx and tx interrupts
- mov.b ipa5, #10011001q ;priority #9: uart1 rx and tx interrupts
- mov.b ieh, #00001111q ;enable uart interrupts
- ;set up timer 0 to 16-bit auto reload (10 ms)
- clr et0 ;no timer 0 interrupt yet
- clr tr0 ;stop timer 0
- clr tf0
- mov.b rtl0, #low 37798 ;set 10 ms rate
- mov.b rth0, #high 37798
- movs.b tl0, #0 ;zero timer
- movs.b th0, #0
- and.b tmod, #11110000q ;set for 16 bit auto reload
-
-
- ;now set up the variables so we're in idle mode
- mov r0, #current_proc
- movs.w [r0], #0 ;set no process running
- mov r0, #run_queue
- movs.b [r0], #0 ;all queues empty
- mov r0, #sleep_queue
- movs.b [r0], #0
- mov r0, #time_running
- movs.b [r0], #0
- ;initialize pt_usp of all processes to zero, so that
- ;there won't appear to be any processes
-
- nop
-clr_proc_tbl:
- mov r1, #proc_table
- mov r2, #max_num_proc
-clr_proc_tbl_loop:
- movs.w [r1+pt_usp], #0
- add r1, #pt_entry_size
- djnz r2, clr_proc_tbl_loop
-clr_events:
- mov r1, #event_table
- mov r2, #max_num_event
-clr_events_loop:
- movs.w [r1+evt_function], #0
- add r1, #evt_entry_size
- djnz r2, clr_events_loop
-
-;now create process table entries for the test programs
- mov r4, #program1
- mov r5, #$F000
- call create_process ;create process for program1
- mov r4, #program2
- mov r5, #$EC00
- call create_process ;create process for program2
- mov r4, #program3
- mov r5, #$E800
- ;call create_process ;create process for program3
-
-
-
- ;now how can we get into user mode for the first time???
- ;normally the kernel is entered by an interrupt (hardware
- ;or software) or a trap (sys call), so we get back to a
- ;user program with reti... but the first time has to be
- ;handled a bit differently
- mov r1, #proc_table
- call d_que_proc ;remove new proc to run from run queue
- call restore_context
- mov r0, #time_running
- movs.b [r0], #0 ;reset "time_running"
- mov r0, #current_proc
- mov [r0], r1 ;set "current_proc" to new process
- popu.b ssel
- popu.b es
- popu.b ds
- popu r0, r1, r2 ;r0=psw, r1=pc_high, r2=pc_low
- popu r3, r4, r5 ;extract r0/r2 reg from stack
- popu r3, r4, r5, r6 ;extract r3/r6 reg from stack
- mov cs, r1l ;set code segment
- clr tf0 ;clear timer0 flag
- setb tr0 ;start timer0
- setb et0 ;enable timer0 interrupt
- setb ea
- mov pswl, r0l
- mov pswh, r0h ;this makes the switch to user mode
- ;and lower priority to 0 (from max)
- jmp [r2] ;jump to the user program
-
-
-
-
-kernel_panic:
-die:
- clr ea
- clr ri_0
-die_loop:
- jnb ri_0, die_loop
- clr ri_0
- jmp $120 ;reboot!
-
-
-
-;unix system calls: (which ones to try first??)
-;process mgt: fork, exec/execve, exit, wait/wait4
-;file i/o: open, read, write, select, ioclt, lseek, close, fcntl
-;signals: kill, signal, alarm, pause
-;pipes: pipe, dup/dup2
-;network/ipc: socket, bind, connect/listen/accept, sendto, recvfrom
-;network/ipc: socketpair, getsockname/getpeername, setsockopt/getsockopt
-;filesystems: chroot/chdir, link, unlink, mkdir, rmdir,
-;filesystems: chown/chmod, stat, rename, truncate
-
-
-
-
-;**************************************************************
-;** **
-;** User Programs **
-;** **
-;**************************************************************
-
-
-
-cout:
- trap #trap_cout
- ret
-
-newline:
- push r4l
- mov r4l, #13
- call cout
- mov r4l, #10
- call cout
- pop r4l
- ret
-
-pstr: PUSH r4
-pstr1: MOVC r4l,[r6+]
- beq pstr2
- AND R4L,#0x7F
- CALL cout
- BR pstr1
-pstr2: POP r4
- RET
-
-phex:
-phex8:
- PUSH.B acc
- RL.B R4L,#4
- AND.B R4L,#15
- ADD.B R4L,#246
- BCC phex_b
- ADD.B R4L,#7
-phex_b: ADD.B R4L,#58
- CALL cout
- POP.B acc
-phex1: PUSH.B acc
- AND.B R4L,#15
- ADD.B R4L,#246
- BCC phex_c
- ADD.B R4L,#7
-phex_c: ADD.B R4L,#58
- CALL cout
- POP.B acc
- RET
-
-phex16:
- PUSH.B acc
- MOV.B R4L,dph
- CALL phex
- MOV.B R4L,dpl
- CALL phex
- POP.B acc
- RET
-
-
-
-
-
- ;program #1 prints "Paul" to serial port #0, with a
- ;fairly long delay between each printing
-program1:
- mov r6, #str_paul
- call pstr
- mov r0, #130
- trap #trap_delay
- jmp program1
-
-str_paul: db "Paul",0
-
-pgm2_speed equ 10 ;number of ticks between led blinks
-
- nop
- ;program #2 blinks the LEDs and prints a "." to the
- ;serial port #0 after every sequence of blinks.
-program2:
- or.b p1cfga, #$C0 ;p1.6 and p1.7 outputs
- or.b p1cfgb, #$C0
-pg2_loop:
- ;br pg2_skip_blink
- setb p1.6
- setb p1.7
- mov r0, #pgm2_speed
- trap #trap_delay
- clr p1.6
- setb p1.7
- mov r0, #pgm2_speed
- trap #trap_delay
- setb p1.6
- setb p1.7
- mov r0, #pgm2_speed
- trap #trap_delay
- setb p1.6
- clr p1.7
- mov r0, #pgm2_speed
- trap #trap_delay
- setb p1.6
- setb p1.7
-
-pg2_skip_blink:
- mov r4l, #'.'
- call cout
- br pg2_loop
-
-program3:
- mov r4l, #'3'
- call cout
- ;mov r6, #test_str
- ;call pstr
- jmp program3
-
-
-test_str: db "This_is_a_test", 0
-
-
-
-
-
-
-
-
-
+++ /dev/null
-; this copy is hacked to write to page 0Fxxxx when receiving
-; an intel-hex download... so it hopefully work on Matt's
-; 16-bit board layout.
-
-;$pagewidth 132t
-
-; This is a hacked copy of paulmon2 which is intended to work
-; with the XA processor. Automatic baud rate detection is not
-; supported, and the extras package is not avaialble. Flash
-; ROM is not supported. Paulmon2 only understands the first 64k
-; of memory, and only recognizes intel-hex with 64k address
-; space. Due to differences in arrangement of the XA, Paulmon2
-; may crash if it receives invalid intel-hex code (untested).
-; See comments in "dnld_ghex" for details about this.
-
-; Other bugs may exist, but the system seems to work.
-
-; Paulmon2 does NOT run in the XA's special 8051 compatibility
-; mode. Paulmon2 shuts off the watchdog timer and runs all
-; code in system mode (highest priority).
-
-;$include xa-g3.equ
-
-acc reg R4L
-dpl reg R6L
-dph reg R6H
-s0con sfr 420h
-ri_0 bit s0con.0
-ti_0 bit s0con.1
-pswl sfr 400h
-psw51 sfr 402h
-tcon sfr 410h
-tr1 bit tcon.6
-s0buf sfr 460h
-wdcon sfr 41fh
-wfeed1 sfr 45dh
-wfeed2 sfr 45eh
-tl1 sfr 452h
-tmod sfr 45ch
-rtl1 sfr 456h
-ssel sfr 403h
-cs sfr 443h
-
-
-; PAULMON2, a user-friendly 8051 monitor, by Paul Stoffregen
-; Please email comments, suggestions, bugs to paul@ece.orst.edu
-
-; It's free. You may copy sections of code from PAULMON2
-; into your own programs, even for commercial purposes.
-; PAULMON2 should only be distributed free of charge, but may
-; be bundled as 'value-added' with other products, such as
-; development boards, CDROMs, etc. Please distribute the
-; PAULMON2.DOC file and other files, not just the object code!
-
-; The PAULMON2.EQU and PAULMON2.HDR files contain valuable
-; information that could help you to write programs for use
-; with PAULMON2.
-
-; PAULMON2 is in the public domain. PAULMON2 is distributed in
-; the hope that it will be useful, but without any warranty;
-; without even the implied warranty of merchantability or fitness
-; for a particular purpose.
-
-
-carry bit pswl.7
-flag0 bit psw51.5
-flag1 bit psw51.1
-
-;---------------------------------------------------------;
-; ;
-; PAULMON2's default configuration ;
-; ;
-;---------------------------------------------------------;
-
-; PAULMON2 should be assembled using the modified AS31 assembler,
-; originally written by Ken Stauffer, many small changes by Paul
-; Stoffregen. This free assembler is available on the web at
-; http://www.ece.orst.edu/~paul/8051-goodies/goodies-index.html
-; As well, these web pages have a fill-out form which makes it
-; very easy to custom configure PAULMON2. Using this form will
-; edit the code for you, run the AS31 assmebler, and send you the
-; object code to program into your chip.
-
-
-vector equ $8000
-
-; These three parameters tell PAULMON2 where the user's memory is
-; installed. "bmem" and "emem" define the space that will be searched
-; for program headers, user installed commands, start-up programs, etc.
-; "bmem" and "emem" should be use so they exclude memory areas where
-; perphreal devices may be mapped, as reading memory from an io chip
-; may reconfigure it unexpectedly. If flash rom is used, "bmem" and "emem"
-; should also include the space where the flash rom is mapped.
-
-pgm EQU $F000 ;default location for the user program
-bmem EQU $0000 ;where is the beginning of memory
-emem EQU $FFFF ;end of the memory
-
-
-; Please note... much of the memory management code only looks at the
-; upper 8 bits of an address, so it's not a good idea to somehow map
-; your memory chips (with complex address decoding logic) into chunks
-; less than 256 bytes. In other words, only using a piece of a flash
-; rom chip and mapping it between C43A to F91B would confuse PAULMON2
-; (as well as require quit a bit of address decoding logic circuitry)
-
-; To set the baud rate, use this formula or set to 0 for auto detection
-; baud_const = 256 - (crystal / (4 * 16 * baud)) <-- for XA chip
-
-;baud_const EQU 247 ;19200 baud w/ 11.0592 MHz (XA)
-;baud_const EQU 253 ;57600 baud w/ 11.0592 MHz (XA)
-baud_const EQU 251 ;57600 baud w/ 18.432 MHz (XA)
-;baud_const EQU 241 ;19200 baud w/ 18.432 MHz (XA)
-;baud_const EQU 236 ;19531 baud w/ 25 MHz (XA)
-
-
-; About download speed: when writing to ram, PAULMON2 can accept data
-; at the maximum baud rate (baud_const=255 or 57600 baud w/ 11.0592 MHz).
-; Most terminal emulation programs introduce intentional delays when
-; sending ascii data, which you would want to turn off for downloading
-; larger programs into ram. For Flash ROM, the maximum speed is set by
-; the time it takes to program each location... 9600 baud seems to work
-; nicely for the AMD 28F256 chip. The "character pacing" delay in a
-; terminal emulation program should be sufficient to download to flash
-; rom and any baud rate.
-
-
-; Several people didn't like the key definations in PAULMON1.
-; Actually, I didn't like 'em either, but I never took the time
-; to change it. Eventually I got used to them, but now it's
-; really easy to change which keys do what in PAULMON2. You
-; can guess what to do below, but don't use lowercase.
-
-help_key EQU '?' ;help screen
-dir_key EQU 'M' ;directory
-run_key EQU 'R' ;run program
-dnld_key EQU 'D' ;download
-upld_key EQU 'U' ;upload
-nloc_key EQU 'N' ;new memory location
-jump_key EQU 'J' ;jump to memory location
-dump_key EQU 'H' ;hex dump memory
-intm_key EQU 'I' ;hex dump internal memory
-edit_key EQU 'E' ;edit memory
-clrm_key EQU 'C' ;clear memory
-erfr_key EQU 'Z' ;erase flash rom
-xdump_key EQU 'X' ;hex dump ext data memory
-
-
-;location of parameter table used by download command
-;sixteen bytes of internal memory are required beginning at this
-;location
-
-dnld_parm EQU $01F0
-stack EQU $01EE
-
-;---------------------------------------------------------;
-; ;
-; Interrupt Vectors ;
-; (and little bits of code crammed in the empty spaces) ;
-; ;
-;---------------------------------------------------------;
-
- ORG 0
-
- dw $8f00, poweron
-breakvec: dw $8f00, vector + breakvec
-tracevec: dw $8f00, vector + tracevec
-stackovvec: dw $8f00, vector + stackovvec
-div0vec: dw $8f00, vector + div0vec
-uretivec: dw $8f00, vector + uretivec
- org $40
-trap0vec: dw $8800, vector + trap0vec
-trap1vec: dw $8800, vector + trap1vec
-trap2vec: dw $8800, vector + trap2vec
-trap3vec: dw $8800, vector + trap3vec
-trap4vec: dw $8800, vector + trap4vec
-trap5vec: dw $8800, vector + trap5vec
-trap6vec: dw $8800, vector + trap6vec
-trap7vec: dw $8800, vector + trap7vec
-trap8vec: dw $8800, vector + trap8vec
-trap9vec: dw $8800, vector + trap9vec
-trap10vec: dw $8800, vector + trap10vec
-trap11vec: dw $8800, vector + trap11vec
-trap12vec: dw $8800, vector + trap12vec
-trap13vec: dw $8800, vector + trap13vec
-trap14vec: dw $8800, vector + trap14vec
-trap15vec: dw $8800, vector + trap15vec
- org $80
-int0vec: dw $8900, vector + int0vec
-tmr0vec: dw $8900, vector + tmr0vec
-int1vec: dw $8900, vector + int1vec
-tmr1vec: dw $8900, vector + tmr1vec
-tmr2vec: dw $8900, vector + tmr2vec
- org $A0
-rxd0vec: dw $8900, vector + rxd0vec
-txd0vec: dw $8900, vector + txd0vec
-rxd1vec: dw $8900, vector + rxd1vec
-txd1vec: dw $8900, vector + txd1vec
- org $100
-swi1vec: dw $8100, vector + swi1vec
-swi2vec: dw $8200, vector + swi2vec
-swi3vec: dw $8300, vector + swi3vec
-swi4vec: dw $8400, vector + swi4vec
-swi5vec: dw $8500, vector + swi5vec
-swi6vec: dw $8600, vector + swi6vec
-swi7vec: dw $8700, vector + swi7vec
-
- org $120
-
- jmp poweron
-
-
-space: MOV.B R4L,#' '
- CALL cout
- RET
-
-dash: MOV.B R4L,#'-'
- CALL cout
- RET
-
-
-;---------------------------------------------------------;
-; ;
-; The jump table for user programs to call ;
-; subroutines within PAULMON ;
-; ;
-;---------------------------------------------------------;
-
-; no jump table anymore... use TRAP or conditional assembly.
-
-
-;---------------------------------------------------------;
-; ;
-; Subroutines for serial I/O ;
-; ;
-;---------------------------------------------------------;
-
-
-;these are the only three routines which access the serial port directly
-;but poweron/autobaud to the initial setup
-
-cin: JNB ri_0,cin
- CLR ri_0
- MOV.B R4L,s0buf
- RET
-cout: JNB ti_0,cout
- CLR ti_0 ;clr ti before the mov to sbuf!
- MOV.B s0buf,R4L
- RET
-esc: ;checks to see if <ESC> is waiting on serial port
- ;C=clear if no <ESC>, C=set if <ESC> pressed
- ;buffer is flushed
- PUSH.B acc
- CLR carry
- JNB ri_0,esc2
- clr ri_0
- MOV.B R4L, s0buf
- CJNE.B R4L,#27,esc2
- SETB carry
-esc2: POP.B acc
- RET
-
-
-;everything else from here on should only access the serial
-;port using cin/cout/etc
-
-
-newline: PUSH.B acc
- MOV.B R4L,#13
- CALL cout
- MOV.B R4L,#10
- CALL cout
- POP.B acc
- RET
-
- ;get 2 digit hex number from serial port
- ; c = set if ESC pressed, clear otherwise
- ; flag0 = set if return w/ no input, clear otherwise
-ghex:
-ghex8: CLR flag0
-ghex8c:
- CALL cin ;get first digit
- CALL upper
- CJNE.B R4L,#27,ghex8f
-ghex8d: SETB carry
- MOVS R4L,#0
- RET
-ghex8f: CJNE.B R4L,#13,ghex8h
- SETB flag0
- CLR carry
- MOVS R4L,#0
- RET
-ghex8h: MOV.B R1L,R4L
- CALL asc2hex
- BCS ghex8c
- XCH.B R4L,R1L ;r2 will hold hex value of 1st digit
- CALL cout
-ghex8j:
- CALL cin ;get second digit
- CALL upper
- CJNE.B R4L,#27,ghex8k
- BR ghex8d
-ghex8k: CJNE.B R4L,#13,ghex8m
- MOV.B R4L,R1L
- CLR carry
- RET
-ghex8m: CJNE.B R4L,#8,ghex8p
-ghex8n: CALL cout
- BR ghex8c
-ghex8p: CJNE.B R4L,#21,ghex8q
- BR ghex8n
-ghex8q: MOV.B R1H,R4L
- CALL asc2hex
- BCS ghex8j
- XCH.B R4L,R1H
- CALL cout
- MOV.B R4L,R1L
- RL.B R4L,#4
- OR.B R4L,R1H
- CLR carry
- RET
-
-
-
-
- ;carry set if esc pressed
- ;flag0 set if return pressed w/ no input
-ghex16:
- MOV.B R1L,#0 ;start out with 0
- MOV.B R1H,#0
- MOV.B R2L,#4 ;number of digits left
- CLR flag0
-
-ghex16c:
- CALL cin
- CALL upper
- CJNE.B R4L,#27,ghex16d
- SETB carry ;handle esc key
- MOVS R4L,#0
- MOV.B dph,R4L
- MOV.B dpl,R4L
- RET
-ghex16d: CJNE.B R4L,#8,ghex16f
- BR ghex16k
-ghex16f: CJNE.B R4L,#127,ghex16g ;handle backspace
-ghex16k: CJNE.B R2L,#4,ghex16e ;have they entered anything yet?
- BR ghex16c
-ghex16e: CALL cout
- CALL ghex16y
- ADDS.B R2L,#1
- BR ghex16c
-ghex16g: CJNE.B R4L,#13,ghex16i ;return key
- MOV.B dph,R1H
- MOV.B dpl,R1L
- CJNE.B R2L,#4,ghex16h
- MOVS R4L,#0
- MOV.B dph,R4L
- MOV.B dpl,R4L
- SETB flag0
-ghex16h: CLR carry
- RET
-ghex16i: MOV.B R2H,R4L ;keep copy of original keystroke
- CALL asc2hex
- BCS ghex16c
- XCH.B R4L,R2H
- CALL cout
- MOV.B R4L,R2H
- PUSH.B acc
- CALL ghex16x
- POP.B acc
- ADD.B R4L,R1L
- MOV.B R1L,R4L
- MOVS R4L,#0
- ADDC.B R4L,R1H
- MOV.B R1H,R4L
- DJNZ.B R2L,ghex16c
- CLR carry
- MOV.B dpl,R1L
- MOV.B dph,R1H
- RET
-
-ghex16x: ;multiply r3-r2 by 16 (shift left by 4)
- MOV.B R4L,R1H
- RL.B R4L,#4
- AND.B R4L,#11110000Q
- MOV.B R1H,R4L
- MOV.B R4L,R1L
- RL.B R4L,#4
- AND.B R4L,#00001111Q
- OR.B R4L,R1H
- MOV.B R1H,R4L
- MOV.B R4L,R1L
- RL.B R4L,#4
- AND.B R4L,#11110000Q
- MOV.B R1L,R4L
- RET
-
-ghex16y: ;divide r3-r2 by 16 (shift right by 4)
- MOV.B R4L,R1L
- RL.B R4L,#4
- AND.B R4L,#00001111Q
- MOV.B R1L,R4L
- MOV.B R4L,R1H
- RL.B R4L,#4
- AND.B R4L,#11110000Q
- OR.B R4L,R1L
- MOV.B R1L,R4L
- MOV.B R4L,R1H
- RL.B R4L,#4
- AND.B R4L,#00001111Q
- MOV.B R1H,R4L
- RET
-
-asc2hex: ;carry set if invalid input
- CLR carry
- PUSH.B R4H
- SUBB.B R4L,#'0'
- MOV.B R4H,R4L
- SUBB.B R4L,#10
- BCS a2h1
- MOV.B R4L,R4H
- SUBB.B R4L,#7
- MOV.B R4H,R4L
-a2h1: MOV.B R4L,R4H
- CLR carry
- AND.B R4L,#11110000Q ;just in case
- JZ a2h2
- SETB carry
-a2h2: MOV.B R4L,R4H
- POP.B R4H
- RET
-
-
-phex:
-phex8:
- PUSH.B acc
- RL.B R4L,#4
- AND.B R4L,#15
- ADD.B R4L,#246
- BCC phex_b
- ADD.B R4L,#7
-phex_b: ADD.B R4L,#58
- CALL cout
- POP.B acc
-phex1: PUSH.B acc
- AND.B R4L,#15
- ADD.B R4L,#246
- BCC phex_c
- ADD.B R4L,#7
-phex_c: ADD.B R4L,#58
- CALL cout
- POP.B acc
- RET
-
-
-phex16:
- PUSH.B acc
- MOV.B R4L,dph
- CALL phex
- MOV.B R4L,dpl
- CALL phex
- POP.B acc
- RET
-
-
-;a not so well documented feature of pstr is that you can print
-;multiple consecutive strings without needing to reload dptr
-;(which takes 3 bytes of code!)... this is useful for inserting
-;numbers or spaces between strings.
-
-pstr: PUSH.B acc
-pstr1: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- ADDS.W R6,#1
- JZ pstr2
- MOV C,R4L.7
- AND.B R4L,#0x7F
- CALL cout
- BCS pstr2
- BR pstr1
-pstr2: POP.B acc
- RET
-
-
-
-;---------------------------------------------------------;
-; ;
-; The 'high-level' stuff to interact with the user ;
-; ;
-;---------------------------------------------------------;
-
-
-menu: ;first we print out the prompt
- MOV.W R6,#prompt1 ;give 'em the first part of prompt
- CALL pcstr
- MOV.B R4L,R3H
- CALL phex
- MOV.B R4L,R3L
- CALL phex
- CALL space
- MOV.W R6,#prompt2
- CALL pstr
-
-
-;now we're past the prompt, so let's get some input
- CALL cin ;get the input
- CALL upper
-
-
-menu1a: CJNE.B R4L,#help_key,menu1b
- MOV.W R6,#help_cmd2
- CALL pcstr
- call help
- jmp menu
-menu1b: CJNE.B R4L,#dir_key,menu1c
- MOV.W R6,#dir_cmd
- CALL pcstr
- call dir
- jmp menu
-menu1c: CJNE.B R4L,#run_key,menu1d
- MOV.W R6,#run_cmd
- CALL pcstr
- call run
- jmp menu
-menu1d: CJNE.B R4L,#dnld_key,menu1e
- MOV.W R6,#dnld_cmd
- CALL pcstr
- call dnld
- jmp menu
-menu1e: CJNE.B R4L,#upld_key,menu1f
- MOV.W R6,#upld_cmd
- CALL pcstr
- call upld
- jmp menu
-menu1f: CJNE.B R4L,#nloc_key,menu1g
- MOV.W R6,#nloc_cmd
- CALL pcstr
- call nloc
- jmp menu
-menu1g: CJNE.B R4L,#jump_key,menu1h
- MOV.W R6,#jump_cmd
- CALL pcstr
- call jump
- jmp menu
-menu1h: CJNE.B R4L,#dump_key,menu1i
- MOV.W R6,#dump_cmd
- CALL pcstr
- call dump
- jmp menu
-menu1i: CJNE.B R4L,#edit_key,menu1j
- MOV.W R6,#edit_cmd
- CALL pcstr
- call edit
- jmp menu
-menu1j: CJNE.B R4L,#clrm_key,menu1l
- MOV.W R6,#clrm_cmd
- CALL pcstr
- call clrm
- jmp menu
-menu1l: CJNE.B R4L,#intm_key,menu1m
- MOV.W R6,#intm_cmd
- CALL pcstr
- call intm
- jmp menu
-menu1m: CJNE.B R4L,#xdump_key,menu1n
- MOV.W R6,#xdump_cmd
- CALL pcstr
- call xdump
- jmp menu
-menu1n:
-
- ;invalid input, no commands to run...
-menu_end: ;at this point, we have not found
- CALL newline ;anything to run, so we give up.
- jmp menu
-
-;..........................................................
-
-;---------------------------------------------------------;
-
-;dnlds1 = "Begin sending Intel HEX format file <ESC> to abort"
-;dnlds2 = "Download aborted"
-;dnlds3 = "Download completed"
-
-
-;16 byte parameter table: (eight 16 bit values)
-; * 0 = lines received
-; * 1 = bytes received
-; * 2 = bytes written
-; * 3 = bytes unable to write
-; * 4 = incorrect checksums
-; * 5 = unexpected begin of line
-; * 6 = unexpected hex digits (while waiting for bol)
-; * 7 = unexpected non-hex digits (in middle of a line)
-
-dnld:
- MOV.W R6,#dnlds1
- CALL pcstr ;"begin sending file <ESC> to abort"
- mov.w r5,#dnld_parm
- mov.b R1L,#8
-dnld0: movs.w [r5+],#0 ;initialize all parameters to 0
- DJNZ.B R1L,dnld0
-
- ;look for begining of line marker ':'
-dnld1: CALL cin
- CJNE.B R4L,#27,dnld2 ;Test for escape
- BR dnld_esc
-dnld2: CJNE.B R4L,#':',dnld2b
- mov.w r5, #dnld_parm
- adds.w [r5+0], #1
- BR dnld3
-dnld2b: ;check to see if it's a hex digit, error if it is
- CALL asc2hex
- BCS dnld1
- mov.w r5, #dnld_parm
- adds.w [r5+12], #1
- BR dnld1
- ;begin taking in the line of data
-dnld3: MOV.B R4L,#'.'
- CALL cout
- MOV.B R2L,#0 ;r4 will count up checksum
- CALL dnld_ghex
- MOV.B R0L,R4L ;R0 = # of data bytes
- MOV.B R2L,R4L
- CALL dnld_ghex
- MOV.B dph,R4L ;High byte of load address
- ADD.B R4L,R2L
- MOV.B R2L,R4L
- CALL dnld_ghex
- MOV.B dpl,R4L ;Low byte of load address
- ADD.B R4L,R2L
- MOV.B R2L,R4L
- CALL dnld_ghex ;Record type
- MOV.B R1L,R4L
- ADD.B R4L,R2L
- MOV.B R2L,R4L
- MOV.B R4L,R1L
- CJNE.B R4L,#1,dnld4 ;End record?
- BR dnld_end
-dnld4:
-dnld5: CALL dnld_ghex ;Get data byte
- MOV.B R1L,R4L
- mov.w r5, #dnld_parm
- adds.w [r5+2], #1
- MOV.B R4L,R1L
- ADD.B R4L,R2L
- MOV.B R2L,R4L
- MOV.B R4L,R1L
- CALL smart_wr ;c=1 if an error writing
- MOVS R4L,#0
- ADDC.B R4L,#2
- MOV.B R0H,R4L
-; 2 = bytes written
-; 3 = bytes unable to write
- rl.b r4l, #1
- movs.b r4h, #0
- mov.w r5, #dnld_parm
- add.w r5, r4
- adds.w [r5], #1
-
- ADDS.W R6,#1
- DJNZ.B R0L,dnld5
-
- CALL dnld_ghex ;get checksum
- ADD.B R4L,R2L
- JZ dnld1 ;should always add to zero
-dnld_sumerr:
- mov.w r5, #dnld_parm
- adds.w [r5+8], #1
- BR dnld1
-
-dnld_end: ;handles the proper end-of-download marker
- CALL dnld_ghex ;get the last checksum
- ;assume no data in this line.
- ADD.B R4L,R2L
- JNZ dnld_sumerr
- CALL dnld_dly
- MOV.W R6,#dnlds3
- CALL pcstr ;"download went ok..."
- ;consume any cr or lf character that may have been
- ;on the end of the last line
- JNB ri_0,dnld_sum
- CALL cin
- BR dnld_sum
-
-dnld_esc: ;handle esc received in the download stream
- CALL dnld_dly
- MOV.W R6,#dnlds2
- CALL pcstr ;"download aborted."
- BR dnld_sum
-
-dnld_dly: ;a short delay since most terminal emulation programs
- ;won't be ready to receive anything immediately after
- ;they've transmitted a file... even on a fast Pentium(tm)
- ;machine with 16550 uarts!
- MOV.B R0L,#0
-dnlddly2: MOV.B R0H,#0
-dnlddly3: DJNZ.B R0H,dnlddly3 ;roughly 128k cycles, appox 0.1 sec
- DJNZ.B R0L,dnlddly2
- RET
-
-
-
-
-
-
-;a special version of ghex just for the download. Does not
-;look for carriage return or backspace. Handles ESC key by
-;poping the return address (I know, nasty, but it saves many
-;bytes of code in this 4k ROM) and then jumps to the esc
-;key handling. This ghex doesn't echo characters, and if it
-;sees ':', it pops the return and jumps to an error handler
-;for ':' in the middle of a line. Non-hex digits also jump
-;to error handlers, depending on which digit.
-
-; XA compatibility issue: This code pops the return address
-; off the stack and does a jump to an error handler. The
-; code should examine the mode bit to see if return addresses
-; are 16 or 32 bits on the stack. As it is, it will probably
-; work in non 16-bit mode (default), but this code could
-; use some attention to this detail nonetheless.
-
-dnld_ghex:
-dnldgh1: CALL cin
- CALL upper
- CJNE.B R4L,#27,dnldgh3
-dnldgh2: POP.B acc ;<-- compatibility problem!!! Check XA mode
- POP.B acc ;<-- and pop correct number of words off stack
- BR dnld_esc
-dnldgh3: CJNE.B R4L,#':',dnldgh5
-dnldgh4:
- mov.w r5, #dnld_parm
- adds.w [r5+10], #1 ;handle unexpected beginning of line
- POP.B acc ;<-- compatibility problem!!! Check XA mode
- POP.B acc ;<-- and pop correct number of words off stack
- JMP dnld3 ;and now we're on a new line!
-dnldgh5: CALL asc2hex
- BCC dnldgh6
- mov.w r5, #dnld_parm
- adds.w [r5+14], #1
- BR dnldgh1
-dnldgh6: MOV.B R1L,R4L ;keep first digit in r2
-dnldgh7: CALL cin
- CALL upper
- CJNE.B R4L,#27,dnldgh8
- BR dnldgh2
-dnldgh8: CJNE.B R4L,#':',dnldgh9
- BR dnldgh4
-dnldgh9: CALL asc2hex
- BCC dnldghA
- mov.w r5, #dnld_parm
- adds.w [r5+14], #1
- BR dnldgh7
-dnldghA: XCH.B R4L,R1L
- RL.B R4L,#4
- OR.B R4L,R1L
- RET
-
-;dnlds4 = "Summary:"
-;dnlds5 = " lines received"
-;dnlds6a = " bytes received"
-;dnlds6b = " bytes written"
-
-dnld_sum: ;print out download summary
- MOV.W R6,#dnlds4
- CALL pcstr
- MOV.w r5, #dnld_parm
- mov.w r6, [r5+]
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds5
- CALL pcstr
- mov.w r6, [r5+]
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds6a
- CALL pcstr
- mov.w r6, [r5+]
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds6b
- CALL pcstr
-dnld_err: ;now print out error summary
- MOV.w r5, #dnld_parm + 6
- mov r1l, #5
-dnlder2:
- mov.w r6, [r5+]
- bne dnlder3 ;any errors?
- DJNZ.B R1L,dnlder2
- ;no errors, so we print the nice message
- MOV.W R6,#dnlds13
- CALL pcstr
- RET
-dnlder3: ;there were errors, so now we print 'em
- MOV.W R6,#dnlds7
- CALL pcstr
- ;but let's not be nasty... only print if necessary
- mov r5, #dnld_parm+6
- mov r6, [r5+]
- beq dnlder4
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds8
- CALL pcstr
-dnlder4:
- mov r6, [r5+]
- beq dnlder5
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds9
- CALL pcstr
-dnlder5:
- mov r6, [r5+]
- beq dnlder6
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds10
- CALL pcstr
-dnlder6:
- mov r6, [r5+]
- beq dnlder7
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds11
- CALL pcstr
-dnlder7:
- mov r6, [r5+]
- beq dnlder8
- CALL space
- CALL pint16u
- MOV.W R6,#dnlds12
- CALL pcstr
-dnlder8: CALL newline
- RET
-
-;dnlds7: = "Errors:"
-;dnlds8: = " bytes unable to write"
-;dnlds9: = " incorrect checksums"
-;dnlds10: = " unexpected begin of line"
-;dnlds11: = " unexpected hex digits"
-;dnlds12: = " unexpected non-hex digits"
-;dnlds13: = "No errors detected"
-
-
-
-;---------------------------------------------------------;
-
-
-jump:
- MOV.W R6,#prompt8
- CALL pcstr
- mov.w r6, r3
- CALL phex16
- MOV.W R6,#prompt4
- CALL pcstr
- CALL ghex16
- JB flag0,jump3
- BCC jump2
- MOV.W R6,#abort
- CALL pcstr
- CALL newline
- RET
-jump2: mov.w r3, r6
-jump3: CALL newline
- MOV.W R6,#runs1
- CALL pcstr
- mov.w r6, r3
- call phex16
- call newline
- mov.w r6, r3
-
-jump_doit: ;jump to user code @dptr (this used by run command also)
- movs.w r0, #0
- push.w r0
- mov.w r0, #$120
- push.w r0
- jmp [r6]
-
-
-;---------------------------------------------------------;
-
-dump:
- MOV.B R1L,#16 ;number of lines to print
- CALL newline
- CALL newline
-dump1:
- push r6
- mov r6, #msg_code
- call pstr
- pop r6
- MOV.B dpl,R3L
- MOV.B dph,R3H
- CALL phex16 ;tell 'em the memory location
- MOV.B R4L,#':'
- CALL cout
- CALL space
- MOV.B R1H,#16 ;r3 counts # of bytes to print
- MOV.B dpl,R3L
- MOV.B dph,R3H
-dump2: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- ADDS.W R6,#1
- CALL phex ;print each byte in hex
- CALL space
- DJNZ.B R1H,dump2
- CALL space ;print a couple extra space
- CALL space
- MOV.B R1H,#16
- MOV.B dpl,R3L
- MOV.B dph,R3H
-dump3: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- ADDS.W R6,#1
- AND.B R4L,#01111111Q ;avoid unprintable characters
- CLR carry
- SUBB.B R4L,#20h
- BCC dump4 ;avoid control characters
- MOV.B R4L,#(' ' - 20h)
-dump4: ADD.B R4L,#20h
- CALL cout
- DJNZ.B R1H,dump3
- CALL newline
- MOV.B R3L,dpl
- MOV.B R3H,dph
- CALL esc
- BCS dump5
- DJNZ.B R1L,dump1 ;loop back up to print next line
-dump5: CALL newline
- RET
-
-msg_code: db "Code:",0
-msg_xram: db "Xram:",0
-
-;---------------------------------------------------------;
-
-
-xdump:
- MOV.B R1L,#16 ;number of lines to print
- CALL newline
- CALL newline
-xdump1:
- push r6
- mov r6, #msg_xram
- call pstr
- pop r6
- MOV.B dpl,R3L
- MOV.B dph,R3H
- CALL phex16 ;tell 'em the memory location
- MOV.B R4L,#':'
- CALL cout
- CALL space
- MOV.B R1H,#16 ;r3 counts # of bytes to print
- MOV.B dpl,R3L
- MOV.B dph,R3H
-xdump2: MOVS R4L,#0
- MOVX r4l,[r6]
- ADDS.W R6,#1
- CALL phex ;print each byte in hex
- CALL space
- DJNZ.B R1H,xdump2
- CALL space ;print a couple extra space
- CALL space
- MOV.B R1H,#16
- MOV.B dpl,R3L
- MOV.B dph,R3H
-xdump3: MOVS R4L,#0
- MOVX r4l,[r6]
- ADDS.W R6,#1
- AND.B R4L,#01111111Q ;avoid unprintable characters
- CLR carry
- SUBB.B R4L,#20h
- BCC xdump4 ;avoid control characters
- MOV.B R4L,#(' ' - 20h)
-xdump4: ADD.B R4L,#20h
- CALL cout
- DJNZ.B R1H,xdump3
- CALL newline
- MOV.B R3L,dpl
- MOV.B R3H,dph
- CALL esc
- BCS xdump5
- DJNZ.B R1L,xdump1 ;loop back up to print next line
-xdump5: CALL newline
- RET
-
-
-
-
-;---------------------------------------------------------;
-
-nloc:
- MOV.W R6,#prompt6
- CALL pcstr
- CALL ghex16
- BCS nloc2
- JB flag0,nloc2
- MOV.B R3L,dpl
- MOV.B R3H,dph
- CALL newline
- CALL newline
- RET
-nloc2: MOV.W R6,#abort
- CALL pcstr
- CALL newline
- RET
-
-;---------------------------------------------------------;
-
-
-edit: ;edit external ram...
- MOV.W R6,#edits1
- CALL pcstr
- MOV.B dpl,R3L
- MOV.B dph,R3H
-edit1: CALL phex16
- MOV.B R4L,#':'
- CALL cout
- CALL space
- MOV.B R4L,#'('
- CALL cout
- MOV.B R3L,dpl
- MOV.B R3H,dph
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CALL phex
- MOV.W R6,#prompt10
- CALL pcstr
- CALL ghex
- JB flag0,edit2
- BCS edit2
- MOV.B dpl,R3L
- MOV.B dph,R3H
- MOVX.B [R6],R4L
- CALL newline
- ADDS.W R6,#1
- MOV.B R3L,dpl
- MOV.B R3H,dph
- JMP edit1
-edit2: MOV.W R6,#edits2
- CALL pcstr
- RET
-
-;---------------------------------------------------------;
-
-dir:
- MOV.W R6,#prompt9
- CALL pcstr
- MOV.B R0L,#21
-dir0a: CALL space
- DJNZ.B R0L,dir0a
- MOV.W R6,#prompt9b
- CALL pcstr
-
- MOV.B dph,#high bmem
-dir1: CALL find ;find the next program in memory
- BCS dir2
-dir_end: CALL newline ;we're done if no more found
- RET
-dir2:
- CALL space
- CALL space
- MOV.B dpl,#32 ;print its name
- CALL pstr
- MOV.B dpl,#32 ;how long is the name
- CALL lenstr
- MOV.B R4L,#33
- CLR carry
- SUBB.B R4L,R0L
- MOV.B R0L,R4L
- MOV.B R4L,#' ' ;print the right # of spaces
-dir3: CALL cout
- DJNZ.B R0L,dir3
- MOV.B dpl,#0
- CALL phex16 ;print the memory location
- MOV.B R0L,#6
- MOV.B R4L,#' '
-dir4: CALL cout
- DJNZ.B R0L,dir4
- MOV.B dpl,#4 ;now figure out what type it is
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- MOV.B R1L,dph ;save this, we're inside a search
-
-dir5: CJNE.B R4L,#254,dir5b
- MOV.W R6,#type1 ;it's an external command
- BR dir7
-dir5b: CJNE.B R4L,#255,dir5c
- MOV.W R6,#type1a ;it's some system thing
- BR dir7
-dir5c: CJNE.B R4L,#253,dir5d
- MOV.W R6,#type1b ;it's a startup routine
- BR dir7
-dir5d: CJNE.B R4L,#35,dir5e
- MOV.W R6,#type2 ;it's an ordinary program
- BR dir7
-dir5e: CJNE.B R4L,#143,dir5f
- MOV.W R6,#type3 ;it's a background task
- BR dir7
-dir5f: CJNE.B R4L,#69,dir5g
- MOV.W R6,#type4 ;it's a data file
- BR dir7
-dir5g:
-dir6: MOV.W R6,#type5 ;who knows what the hell it is
-
-dir7: CALL pcstr ;print out the type
- MOV.B dph,R1L ;go back and find the next one
- CALL newline
- CJNE.B dph,#high emem, dir8 ;did we just print the last one?
- JMP dir_end
-dir8: ADDS.B dph,#1
- JMP dir1
-
-
-; type1=Ext Command
-; type1a=Misc System Thing
-; type1b=Power-Up Code
-; type2=Program
-; type3=Background Task
-; type4=Data File
-; type5=???????
-
-;---------------------------------------------------------;
-
-
-run:
- CALL newline
- CALL newline
- jmp 0xF000
-
-
-;---------------------------------------------------------;
-
-help:
- MOV.W R6,#help1txt
- CALL pcstr
- MOV.B R2L,#help_key
- MOV.W R6,#help_cmd
- CALL help2
- MOV.B R2L,#dir_key
- MOV.W R6,#dir_cmd
- CALL help2
- MOV.B R2L,#run_key
- MOV.W R6,#run_cmd
- CALL help2
- MOV.B R2L,#dnld_key
- MOV.W R6,#dnld_cmd
- CALL help2
- MOV.B R2L,#upld_key
- MOV.W R6,#upld_cmd
- CALL help2
- MOV.B R2L,#nloc_key
- MOV.W R6,#nloc_cmd
- CALL help2
- MOV.B R2L,#jump_key
- MOV.W R6,#jump_cmd
- CALL help2
- MOV.B R2L,#dump_key
- MOV.W R6,#dump_cmd
- CALL help2
- MOV.B R2L,#xdump_key
- MOV.W R6,#xdump_cmd
- CALL help2
- MOV.B R2L,#intm_key
- MOV.W R6,#intm_cmd
- CALL help2
- MOV.B R2L,#edit_key
- MOV.W R6,#edit_cmd
- CALL help2
- MOV.B R2L,#clrm_key
- MOV.W R6,#clrm_cmd
- CALL help2
- MOV.W R6,#help2txt
- CALL pcstr
- MOV.W R6,#bmem
-help3: CALL find
- BCC help4
- MOV.B dpl,#4
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R4L,#254,help3a ;only FE is an ext command
- CALL space
- CALL space
- ADDS.B dpl,#1
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CALL cout
- CALL dash
- CALL space
- MOV.B dpl,#32
- CALL pstr
- CALL newline
-help3a: ADDS.B dph,#1
- BR help3
-help4:
- CALL newline
- RET
-
-help2: ;print 11 standard lines
- CALL space ;given key in R4 and name in dptr
- CALL space
- MOV.B R4L,R2L
- CALL cout
- CALL dash
- CALL space
- CALL pcstr
- CALL newline
- RET
-
-;---------------------------------------------------------;
-
-upld:
-
- CALL get_mem
- ;assume we've got the beginning address in r3/r2
- ;and the final address in r5/r4 (r4=lsb)...
-
- ;print out what we'll be doing
- MOV.W R6,#uplds3
- CALL pcstr
- MOV.B R4L,R1H
- CALL phex
- MOV.B R4L,R1L
- CALL phex
- MOV.W R6,#uplds4
- CALL pcstr
- MOV.B R4L,R2H
- CALL phex
- MOV.B R4L,R2L
- CALL phex
- CALL newline
-
- ;need to adjust end location by 1...
- MOV.B dph,R2H
- MOV.B dpl,R2L
- ADDS.W R6,#1
- MOV.B R2L,dpl
- MOV.B R2H,dph
-
- MOV.W R6,#prompt7
- CALL pcstr
- CALL cin
- CJNE.B R4L,#27,upld2e
- JMP abort_it
-upld2e: CALL newline
- MOV.B dpl,R1L
- MOV.B dph,R1H
-
-upld3: MOV.B R4L,R2L ;how many more bytes to output??
- CLR carry
- SUBB.B R4L,dpl
- MOV.B R1L,R4L
- MOV.B R4L,R2H
- SUBB.B R4L,dph
- JNZ upld4 ;if >256 left, then do next 16
- MOV.B R4L,R1L
- JZ upld7 ;if we're all done
- AND.B R4L,#11110000Q
- JNZ upld4 ;if >= 16 left, then do next 16
- BR upld5 ;otherwise just finish it off
-upld4: MOV.B R1L,#16
-upld5: MOV.B R4L,#':' ;begin the line
- CALL cout
- MOV.B R4L,R1L
- CALL phex ;output # of data bytes
- CALL phex16 ;output memory location
- MOV.B R4L,dph
- ADD.B R4L,dpl
- ADD.B R4L,R1L
- MOV.B R1H,R4L ;r3 will become checksum
- MOVS R4L,#0
- CALL phex ;output 00 code for data
-upld6: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CALL phex ;output each byte
- ADD.B R4L,R1H
- MOV.B R1H,R4L
- ADDS.W R6,#1
- DJNZ.B R1L,upld6 ;do however many bytes we need
- MOV.B R4L,R1H
- CPL.B R4L
- ADDS.B R4L,#1
- CALL phex ;and finally the checksum
- CALL newline
- CALL esc
- BCC upld3 ;keep working if no esc pressed
- BR abort_it
-upld7: MOV.B R4L,#':'
- CALL cout
- MOVS R4L,#0
- CALL phex
- CALL phex
- CALL phex
- ADDS.B R4L,#1
- CALL phex
- MOV.B R4L,#255
- CALL phex
-upld8: CALL newline
- CALL newline
- RET
-
-
-;---------------------------------------------------------;
-
-get_mem: ;this thing gets the begin and end locations for
- ;a few commands. If an esc or enter w/ no input,
- ;it pops it's own return and returns to the menu
- ;(nasty programming, but we need tight code for 4k rom)
- CALL newline
- CALL newline
- MOV.W R6,#beg_str
- CALL pcstr
- CALL ghex16
- BCS pop_it
- JB flag0,pop_it
- PUSH.B dph
- PUSH.B dpl
- CALL newline
- MOV.W R6,#end_str
- CALL pcstr
- CALL ghex16
- MOV.B R2H,dph
- MOV.B R2L,dpl
- POP.B acc
- MOV.B R1L,R4L
- POP.B acc
- MOV.B R1H,R4L
- BCS pop_it
- JB flag0,pop_it
- CALL newline
- RET
-
-pop_it: POP.B acc
- POP.B acc
-abort_it:
- CALL newline
- MOV.W R6,#abort
- CALL pcstr
- CALL newline
- RET
-
-clrm:
- CALL get_mem
- MOV.W R6,#sure
- CALL pcstr
- CALL cin
- CALL upper
- CJNE.B R4L,#'Y',abort_it
- CALL newline
- CALL newline
- ;now we actually do it
-
-clrm2: MOV.B dph,R1H
- MOV.B dpl,R1L
-clrm3: MOVS R4L,#0
- CALL smart_wr
- cmp.w r6, r2
- bne clrm4
- RET
-clrm4: ADDS.W R6,#1
- BR clrm3
-
-
-
-;---------------------------------------------------------;
-
-intm: CALL newline
- MOVs.w r5,#0
-intm2: CALL newline
- CJNE.w r5, #512, intm3
- CALL newline
- RET
-intm3: mov.b r4l,r5h
- call phex
- MOV.B R4L,R5L
- CALL phex
- MOV.B R4L,#':'
- CALL cout
-intm4: CALL space
- MOV.B R4L,[r5+]
- CALL phex
- MOV.B R4L,R5L
- AND.B R4L,#00001111Q
- JNZ intm4
- BR intm2
-
-
-
-;---------------------------------------------------------;
-; ;
-; Subroutines for memory managment and non-serial I/O ;
-; ;
-;---------------------------------------------------------;
-
-
-;finds the next header in the external memory.
-; Input DPTR=point to start search (only MSB used)
-; Output DPTR=location of next module
-; C=set if a header found, C=clear if no more headers
-find: MOV.B dpl,#0
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R4L,#0xA5,find3
- ADDS.W R6,#1
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R4L,#0xE5,find3
- ADDS.W R6,#1
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R4L,#0xE0,find3
- ADDS.W R6,#1
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R4L,#0xA5,find3
- MOV.B dpl,#0 ;found one here!
- SETB carry
- RET
-find3:
- CJNE.B dph, #high emem, find4 ;did we just check the end
- CLR carry
- RET
-find4: ADDS.B dph,#1 ;keep on searching
- BR find
-
-
-
-
-;Write to ordinary RAM. Carry bit will indicate
-;if the value was successfully written, C=1 if not written.
-
-
-smart_wr:
- PUSH.B acc
- PUSH.B R4H
- MOV.B R4H,R4L
-wr_ram: MOV.B R4L,R4H
- MOVX.B [R6],R4L ;write the value to memory
- MOVS R4L,#0
- MOVC.B A,[A+dptr] ;read it back from code memory
- CLR carry
- SUBB.B R4L,R4H
- JZ smwrok
- MOVX.B R4L,[R6] ;read it back from data memory
- CLR carry
- SUBB.B R4L,R4H
- JZ smwrok
-smwrbad: SETB carry
- BR smwrxit
-smwrok: CLR carry
-smwrxit: POP.B R4H
- POP.B acc
- RET
-
-
-
-;---------------------------------------------------------;
-; ;
-; Power-On initialization code and such... ;
-; ;
-;---------------------------------------------------------;
-
-;first the hardware has to get initialized.
-
-poweron:
- mov.w r7, #stack
- mov.b wdcon, #0 ;shut off watchdog
- mov.b wfeed1, #$a5
- mov.b wfeed2, #$5a
-
- ;or.b p1cfga, #$C0 ;for testing
- ;or.b p1cfgb, #$C0 ;for testing
-
- ;clr p1.7 ;for testing
-
- ;no automatic baud rate detection anymore
-autobaud:
- MOV.B tcon,#0
- MOV.B R4L,#baud_const
- MOV.B tl1,R4L
- MOV.B rtl1,R4L
- MOV.B tmod,#$22 ;set timer #1 for 8 bit auto-reload
- MOV.B s0con,#$52
- SETB tr1 ;start the baud rate timer
- MOV.w r5, #2000
-ab_loop1: DJNZ.w r5, ab_loop1
-
- ;clr p1.6 ;for testing
-
-
-welcome:
- MOV.B R0L,#24
-welcm2: CALL newline
- DJNZ.B R0L,welcm2
-
- ;setb p1.7 ;for testing
-
- MOV.B R0L,#15
- MOV.B R4L,#' '
-welcm4: CALL cout
- DJNZ.B R0L,welcm4
- MOV.W R6,#logon1
- CALL pcstr
- MOV.W R6,#logon2
- CALL pcstr
- ;CALL dir ;skip dir for now
- mov.w r3, #pgm
- JMP menu
-
-
-
-
-
-
-;---------------------------------------------------------;
-; ;
-; More subroutines, but less frequent used ;
-; ;
-;---------------------------------------------------------;
-
-
-
-
-
-pint8u: ;prints the unsigned 8 bit value in Acc in base 10
- PUSH.B R4H
- PUSH.B acc
- BR pint8b
-
-pint8: ;prints the signed 8 bit value in Acc in base 10
- PUSH.B R4H
- PUSH.B acc
- JNB R4L.7,pint8b
- MOV.B R4L,#'-'
- CALL cout
- POP.B acc
- PUSH.B acc
- CPL.B R4L
- ADD.B R4L,#1
-pint8b: MOV.B R4H,#100
- DIVU.B R4L,R4H
- SETB flag0
- JZ pint8c
- CLR flag0
- ADD.B R4L,#'0'
- CALL cout
-pint8c: MOV.B R4L,R4H
- MOV.B R4H,#10
- DIVU.B R4L,R4H
- JNB flag0,pint8d
- JZ pint8e
-pint8d: ADD.B R4L,#'0'
- CALL cout
-pint8e: MOV.B R4L,R4H
- ADD.B R4L,#'0'
- CALL cout
- POP.B acc
- POP.B R4H
- RET
-
-
-
- ;print 16 bit unsigned integer in DPTR (r6), using base 10.
-pint16u:
- push.w r2, r3, r4
- CLR flag0
-pint16a: ;ten-thousands digit
- mov.w r2, r6
- movs.w r3, #0
- div.d r2, #10000
- xch r2, r3
- mov.b r4l, r3l
- JZ pint16b
- ADD.B R4L,#'0'
- CALL cout
- SETB flag0
-pint16b: ;thousands digit
- movs.w r3, #0
- div.d r2, #1000
- xch r2, r3
- mov.b r4l, r3l
- JNZ pint16c
- JNB flag0,pint16d
-pint16c: ADD.B R4L,#'0'
- CALL cout
- SETB flag0
-pint16d: ;hundreds digit
- div.w r2, #100
- xch r2h, r2l
- mov.b r4l, r2h
- JNZ pint16e
- JNB flag0,pint16f
-pint16e: ADD.B R4L,#'0'
- CALL cout
- SETB flag0
-pint16f: ;tens digit
- DIVU.B R2L, #10
- mov.b r4l, r2l
- JNZ pint16g
- JNB flag0,pint16h
-pint16g: ADD.B R4L,#'0'
- CALL cout
-pint16h: ;ones digit
- MOV.B R4L,R2h ;and finally the ones digit
- ADD.B R4L,#'0'
- CALL cout
- pop.w r2, r3, r4
- RET
-
-
-
-upper: ;converts the ascii code in Acc to uppercase, if it is lowercase
- PUSH.B acc
- CLR carry
- SUBB.B R4L,#97
- BCS upper2 ;is it a lowercase character
- SUBB.B R4L,#26
- BCC upper2
- POP.B acc
- ADD.B R4L,#224 ;convert to uppercase
- RET
-upper2: POP.B acc ;don't change anything
- RET
-
-
-lenstr: MOV.B R0L,#0 ;returns length of a string in r0
- PUSH.B acc
-lenstr1: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- JZ lenstr2
- MOV C,R4L.7
- ADDS.B R0L,#1
- BCS lenstr2
- ADDS.W R6,#1
- BR lenstr1
-lenstr2: POP.B acc
- RET
-
-
-;pcstr prints the compressed strings. A dictionary of 128 words is
-;stored in 4 bit packed binary format. When pcstr finds a byte in
-;a string with the high bit set, it prints the word from the dictionary.
-;A few bytes have special functions and everything else prints as if
-;it were an ordinary string.
-
-; special codes for pcstr:
-; 0 = end of string
-; 13 = CR/LF
-; 14 = CR/LF and end of string
-; 31 = next word code should be capitalized
-
-pcstr: push r0, r2, r4
- SETB flag1
- SETB flag0
-pcstr1: MOVS R4L,#0
- MOVC.B A,[A+dptr]
- ADDS.W R6,#1
- JZ pcstr2
- JB R4L.7,decomp
- AND.B R4L,#0x7F
-pcstrs1: CJNE.B R4L,#13,pcstrs2
- CALL newline
- SETB flag1
- BR pcstr1
-pcstrs2: CJNE.B R4L,#31,pcstrs3
- CLR flag0
- BR pcstr1
-pcstrs3: CJNE.B R4L,#14,pcstrs4
- CALL newline
- BR pcstr2
-pcstrs4:
- CLR flag1
- CALL cout
- BR pcstr1
-pcstr2: pop r0, r2, r4
- RET
-
-;dcomp actually takes care of printing a word from the dictionary
-
-; dptr = position in packed words table
-; r4=0 if next nibble is low, r4=255 if next nibble is high
-
-decomp: AND.B R4L,#0x7F
- MOV.B R0L,R4L ;r0 counts which word
- JB flag1,decomp1 ;avoid leading space if first word
- CALL space
-decomp1: CLR flag1
- push r6
- MOV.W R6,#words
- MOV.B R2L,#0
- MOV.B R4L,R0L
- JZ dcomp3
- ;here we must seek past all the words in the table
- ;that come before the one we're supposed to print
- MOV.B R0H,R4L
-dcomp2: CALL get_next_nibble
- JNZ dcomp2
- ;when we get here, a word has been skipped... keep doing
- ;this until we're pointing to the correct one
- DJNZ.B R0H,dcomp2
-dcomp3: ;now we're pointing to the correct word, so all we have
- ;to do is print it out
- CALL get_next_nibble
- JZ dcomp_end
- CJNE.B R4L,#15,dcomp4
- ;the character is one of the 12 least commonly used
- CALL get_next_nibble
- ADDS.B R4L,#1
- MOVC.B A,[A+pc]
- BR dcomp5
- DB "hfwgybxvkqjz"
-dcomp4: ;the character is one of the 14 most commonly used
- ADDS.B R4L,#1
- MOVC.B A,[A+pc]
- BR dcomp5
- DB "etarnisolumpdc"
-dcomp5: ;decide if it should be uppercase or lowercase
- MOV C,flag0
- MOV R4L.5,C
- SETB flag0
- CJNE.B R0L,#20,dcomp6
- CLR R4L.5
-dcomp6: CJNE.B R0L,#12,dcomp7
- CLR R4L.5
-dcomp7: CALL cout
- BR dcomp3
-dcomp_end:
- pop r6
- JMP pcstr1
-
-get_next_nibble: ;...and update dptr and r4, of course
- MOVS R4L,#0
- MOVC.B A,[A+dptr]
- CJNE.B R2L,#0,gnn2
- MOV.B R2L,#255
- AND.B R4L,#00001111Q
- RET
-gnn2: MOV.B R2L,#0
- ADDS.W R6,#1
- RL.B R4L,#4
- AND.B R4L,#00001111Q
- RET
-
-
-;---------------------------------------------------------;
-; ;
-; Here begins the data tables and strings ;
-; ;
-;---------------------------------------------------------;
-
-;this is the dictionary of 128 words used by pcstr.
-
-words:
- DB 0x82,0x90,0xE8,0x23,0x86,0x05,0x4C,0xF8
- DB 0x44,0xB3,0xB0,0xB1,0x48,0x5F,0xF0,0x11
- DB 0x7F,0xA0,0x15,0x7F,0x1C,0x2E,0xD1,0x40
- DB 0x5A,0x50,0xF1,0x03,0xBF,0xBA,0x0C,0x2F
- DB 0x96,0x01,0x8D,0x3F,0x95,0x38,0x0D,0x6F
- DB 0x5F,0x12,0x07,0x71,0x0E,0x56,0x2F,0x48
- DB 0x3B,0x62,0x58,0x20,0x1F,0x76,0x70,0x32
- DB 0x24,0x40,0xB8,0x40,0xE1,0x61,0x8F,0x01
- DB 0x34,0x0B,0xCA,0x89,0xD3,0xC0,0xA3,0xB9
- DB 0x58,0x80,0x04,0xF8,0x02,0x85,0x60,0x25
- DB 0x91,0xF0,0x92,0x73,0x1F,0x10,0x7F,0x12
- DB 0x54,0x93,0x10,0x44,0x48,0x07,0xD1,0x26
- DB 0x56,0x4F,0xD0,0xF6,0x64,0x72,0xE0,0xB8
- DB 0x3B,0xD5,0xF0,0x16,0x4F,0x56,0x30,0x6F
- DB 0x48,0x02,0x5F,0xA8,0x20,0x1F,0x01,0x76
- DB 0x30,0xD5,0x60,0x25,0x41,0xA4,0x2C,0x60
- DB 0x05,0x6F,0x01,0x3F,0x26,0x1F,0x30,0x07
- DB 0x8E,0x1D,0xF0,0x63,0x99,0xF0,0x42,0xB8
- DB 0x20,0x1F,0x23,0x30,0x02,0x7A,0xD1,0x60
- DB 0x2F,0xF0,0xF6,0x05,0x8F,0x93,0x1A,0x50
- DB 0x28,0xF0,0x82,0x04,0x6F,0xA3,0x0D,0x3F
- DB 0x1F,0x51,0x40,0x23,0x01,0x3E,0x05,0x43
- DB 0x01,0x7A,0x01,0x17,0x64,0x93,0x30,0x2A
- DB 0x08,0x8C,0x24,0x30,0x99,0xB0,0xF3,0x19
- DB 0x60,0x25,0x41,0x35,0x09,0x8E,0xCB,0x19
- DB 0x12,0x30,0x05,0x1F,0x31,0x1D,0x04,0x14
- DB 0x4F,0x76,0x12,0x04,0xAB,0x27,0x90,0x56
- DB 0x01,0x2F,0xA8,0xD5,0xF0,0xAA,0x26,0x20
- DB 0x5F,0x1C,0xF0,0xF3,0x61,0xFE,0x01,0x41
- DB 0x73,0x01,0x27,0xC1,0xC0,0x84,0x8F,0xD6
- DB 0x01,0x87,0x70,0x56,0x4F,0x19,0x70,0x1F
- DB 0xA8,0xD9,0x90,0x76,0x02,0x17,0x43,0xFE
- DB 0x01,0xC1,0x84,0x0B,0x15,0x7F,0x02,0x8B
- DB 0x14,0x30,0x8F,0x63,0x39,0x6F,0x19,0xF0
- DB 0x11,0xC9,0x10,0x6D,0x02,0x3F,0x91,0x09
- DB 0x7A,0x41,0xD0,0xBA,0x0C,0x1D,0x39,0x5F
- DB 0x07,0xF2,0x11,0x17,0x20,0x41,0x6B,0x35
- DB 0x09,0xF7,0x75,0x12,0x0B,0xA7,0xCC,0x48
- DB 0x02,0x3F,0x64,0x12,0xA0,0x0C,0x27,0xE3
- DB 0x9F,0xC0,0x14,0x77,0x70,0x11,0x40,0x71
- DB 0x21,0xC0,0x68,0x25,0x41,0xF0,0x62,0x7F
- DB 0xD1,0xD0,0x21,0xE1,0x62,0x58,0xB0,0xF3
- DB 0x05,0x1F,0x73,0x30,0x77,0xB1,0x6F,0x19
- DB 0xE0,0x19,0x43,0xE0,0x58,0x2F,0xF6,0xA4
- DB 0x14,0xD0,0x23,0x03,0xFE,0x31,0xF5,0x14
- DB 0x30,0x99,0xF8,0x03,0x3F,0x64,0x22,0x51
- DB 0x60,0x25,0x41,0x2F,0xE3,0x01,0x56,0x27
- DB 0x93,0x09,0xFE,0x11,0xFE,0x79,0xBA,0x60
- DB 0x75,0x42,0xEA,0x62,0x58,0xA0,0xE5,0x1F
- DB 0x53,0x4F,0xD1,0xC0,0xA3,0x09,0x42,0x53
- DB 0xF7,0x12,0x04,0x62,0x1B,0x30,0xF5,0x05
- DB 0xF7,0x69,0x0C,0x35,0x1B,0x70,0x82,0x2F
- DB 0x2F,0x14,0x4F,0x51,0xC0,0x64,0x25,0x00
-
-;STR
-
-logon1: DB "Welcome",128,148,"2 (beta7,XA) by",31,248,31,254,13,14
-logon2: DB 32,32,"See",148,"2.DOC,",148,"2.EQU",164
- DB 148,"2.HDR",180,213,141,".",14
-abort: DB " ",31,158,31,160,"!",14
-prompt1: DB 148,"2 (beta7,XA) Loc:",0
-prompt2: DB ">",160
-prompt3: DB 134,202,130,'(',0
-prompt4: DB "),",149,140,128,200,": ",0
-prompt5: DB 31,151,130,195,"s",199,166,131,","
- DB 186," JUMP",128,134,161,"r",130,13,14
-prompt6: DB 13,13,31,135,131,129,": ",0
-prompt7: DB 31,228,251," key: ",0
-prompt8: DB 13,13,31,136,128,131,129," (",0
-prompt9: DB 13,13,31,130,31,253,0
-prompt9b: DB 31,129,32,32,32,32,32,31,201,14
-prompt10: DB ") ",31,135,31,178,": ",0
-beg_str: DB "First",31,129,": ",0
-end_str: DB "Last",31,129,":",32,32,0
-sure: DB 31,185,161," sure?",0
-edits1: DB 13,13,31,156,154,146,",",140,128,200,14
-edits2: DB " ",31,156,193,",",142,129,247,13,14
-dnlds1: DB 13,13,31,159," ascii",249,150,31,152,132,137
- DB ",",149,140,128,160,13,14
-dnlds2: DB 13,31,138,160,"ed",13,14
-dnlds3: DB 13,31,138,193,"d",13,14
-dnlds4: DB "Summary:",14
-dnlds5: DB " ",198,"s",145,"d",14
-dnlds6a: DB " ",139,145,"d",14
-dnlds6b: DB " ",139," written",14
-dnlds7: DB 31,155,":",14
-dnlds8: DB " ",139," unable",128," write",14
-dnlds9: DB 32,32,"bad",245,"s",14
-dnlds10: DB " ",133,159,150,198,14
-dnlds11: DB " ",133,132,157,14
-dnlds12: DB " ",133," non",132,157,14
-dnlds13: DB 31,151,155," detected",13,14
-runs1: DB 13,134,"ning",130,":",13,14
-uplds3: DB 13,13,"Sending",31,152,132,137,172,32,32,0
-uplds4: DB " ",128,32,32,0
-help1txt: DB 13,13,"Standard",31,158,"s",14
-help2txt: DB 31,218,31,244,"ed",31,158,"s",14
-type1: DB 31,154,158,0
-type1a: DB 31,223,0
-type1b: DB 31,143,31,226,31,170,0
-type2: DB 31,130,0
-type3: DB "Reserved",0
-type4: DB 31,239,137,0
-type5: DB "???",0
-help_cmd: DB 31,142,215,209,0
-help_cmd2: DB 31,215,0
-dir_cmd: DB 31,209,130,"s",0
-run_cmd: DB 31,134,130,0
-dnld_cmd: DB 31,138,0
-upld_cmd: DB 31,147,0
-nloc_cmd: DB 31,135,129,0
-jump_cmd: DB 31,136,128,131,129,0
-dump_cmd: DB 31,132,219,154," code",131,0
-xdump_cmd: db 31,132,219,154," data",131,0
-intm_cmd: DB 31,132,219,192,131,0
-edit_cmd: DB 31,156,154,146,0
-clrm_cmd: DB 31,237,131,0
-erfr_cmd: DB 31,203,153,144,0
-
-
-
-
-;this code attempts to switch from development mode to run mode
-;on the xa_tiny (8-bit data bus) development board.
-
- org 0x7000
-
-es sfr 442h
-pswh sfr 401h
-
- ; a bunch of nops, to hopefully flush the xa prefetch buffer
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-
- ;make a read from location 0x0EF000 to switch modes
- mov.b es, #0x0E
- mov r0, #0xF000
- setb ssel.0
- mov.b r4l, [r0] ;make the mode switch
- mov.b r4l, [r0] ;make the mode switch
- mov.b r4l, [r0] ;make the mode switch
- mov.b r4l, [r0] ;make the mode switch
-
- ;now read the start vector from location zero
- movs.b es, #0
- movs r0, #0
- movc r1l, [r0+] ;read psw value into r1
- movc r1h, [r0+]
- movc r2l, [r0+] ;read start address into r2
- movc r2h, [r0+]
-
- movs.b ssel, #0
- mov.b pswl, r1l
- mov.b pswh, r1h
- jmp [r2]
-
-
-
+++ /dev/null
-add flag to all symbol structure to remember if it was a line label...
-if a symbol which was a line label is used in immediate addressing,
-it must be considered a branch target.
--- maybe adding an align directive would be enough...
-
-write error messages into list file
-
+++ /dev/null
-%{
-/* This file is part of Paul's XA51 Assembler, Copyright 1997,2002 Paul Stoffregen
- *
- * Paul's XA51 Assembler is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2.
- *
- * Paul's XA51 Assembler is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* Author contact: paul@pjrc.com */
-
-#include <stdio.h>
-#include <string.h>
-#include "xa_main.h"
-#include "xa_asm.tab.h"
-
-extern int inst_size, yylval;
-char line_text[MAX_LINE]={'\0'}, last_line_text[MAX_LINE];
-char lex_sym_name[MAX_SYMBOL];
-extern char base_symbol_name[];
-#define LIST if (p3) strcat(line_text, yytext)
-%}
-
-%%
-
-add\.w {LIST; inst_size=SIZE16; return ADD;}
-add\.b {LIST; inst_size=SIZE8; return ADD;}
-add {LIST; inst_size=UNKNOWN; return ADD;}
-addc\.w {LIST; inst_size=SIZE16; return ADDC;}
-addc\.b {LIST; inst_size=SIZE8; return ADDC;}
-addc {LIST; inst_size=UNKNOWN; return ADDC;}
-adds\.w {LIST; inst_size=SIZE16; return ADDS;}
-adds\.b {LIST; inst_size=SIZE8; return ADDS;}
-adds {LIST; inst_size=UNKNOWN; return ADDS;}
-and\.w {LIST; inst_size=SIZE16; return AND;}
-and\.b {LIST; inst_size=SIZE8; return AND;}
-and {LIST; inst_size=UNKNOWN; return AND;}
-anl {LIST; inst_size=UNKNOWN; return ANL;}
-asl\.d {LIST; inst_size=SIZE32; return ASL;}
-asl\.w {LIST; inst_size=SIZE16; return ASL;}
-asl\.b {LIST; inst_size=SIZE8; return ASL;}
-asl {LIST; inst_size=UNKNOWN; return ASL;}
-asr\.d {LIST; inst_size=SIZE32; return ASR;}
-asr\.w {LIST; inst_size=SIZE16; return ASR;}
-asr\.b {LIST; inst_size=SIZE8; return ASR;}
-asr {LIST; inst_size=UNKNOWN; return ASR;}
-bcc {LIST; inst_size=UNKNOWN; return BCC;}
-bcs {LIST; inst_size=UNKNOWN; return BCS;}
-beq {LIST; inst_size=UNKNOWN; return BEQ;}
-bg {LIST; inst_size=UNKNOWN; return BG;}
-bge {LIST; inst_size=UNKNOWN; return BGE;}
-bgt {LIST; inst_size=UNKNOWN; return BGT;}
-bkpt {LIST; inst_size=UNKNOWN; return BKPT;}
-bl {LIST; inst_size=UNKNOWN; return BL;}
-ble {LIST; inst_size=UNKNOWN; return BLE;}
-blt {LIST; inst_size=UNKNOWN; return BLT;}
-bmi {LIST; inst_size=UNKNOWN; return BMI;}
-bne {LIST; inst_size=UNKNOWN; return BNE;}
-bnv {LIST; inst_size=UNKNOWN; return BNV;}
-bov {LIST; inst_size=UNKNOWN; return BOV;}
-bpl {LIST; inst_size=UNKNOWN; return BPL;}
-br {LIST; inst_size=UNKNOWN; return BR;}
-call {LIST; inst_size=UNKNOWN; return CALL;}
-cjne\.w {LIST; inst_size=SIZE16; return CJNE;}
-cjne\.b {LIST; inst_size=SIZE8; return CJNE;}
-cjne {LIST; inst_size=UNKNOWN; return CJNE;}
-clr {LIST; inst_size=UNKNOWN; return CLR;}
-cmp\.w {LIST; inst_size=SIZE16; return CMP;}
-cmp\.b {LIST; inst_size=SIZE8; return CMP;}
-cmp {LIST; inst_size=UNKNOWN; return CMP;}
-cpl\.w {LIST; inst_size=SIZE16; return CPL;}
-cpl\.b {LIST; inst_size=SIZE8; return CPL;}
-cpl {LIST; inst_size=UNKNOWN; return CPL;}
-da\.b {LIST; inst_size=SIZE8; return DA;}
-da {LIST; inst_size=UNKNOWN; return DA;}
-div\.d {LIST; inst_size=SIZE32; return DIV;}
-div\.w {LIST; inst_size=SIZE16; return DIV;}
-div\.b {LIST; inst_size=SIZE8; return DIV;}
-div {LIST; inst_size=UNKNOWN; return DIV;}
-divu\.d {LIST; inst_size=SIZE32; return DIVU;}
-divu\.w {LIST; inst_size=SIZE16; return DIVU;}
-divu\.b {LIST; inst_size=SIZE8; return DIVU;}
-divu {LIST; inst_size=UNKNOWN; return DIVU;}
-djnz\.w {LIST; inst_size=SIZE16; return DJNZ;}
-djnz\.b {LIST; inst_size=SIZE8; return DJNZ;}
-djnz {LIST; inst_size=UNKNOWN; return DJNZ;}
-fcall {LIST; inst_size=UNKNOWN; return FCALL;}
-fjmp {LIST; inst_size=UNKNOWN; return FJMP;}
-jb {LIST; inst_size=UNKNOWN; return JB;}
-jbc {LIST; inst_size=UNKNOWN; return JBC;}
-jmp {LIST; inst_size=UNKNOWN; return JMP;}
-jnb {LIST; inst_size=UNKNOWN; return JNB;}
-jnz {LIST; inst_size=UNKNOWN; return JNZ;}
-jz {LIST; inst_size=UNKNOWN; return JZ;}
-lea\.w {LIST; inst_size=SIZE16; return LEA;}
-lea {LIST; inst_size=UNKNOWN; return LEA;}
-lsr\.d {LIST; inst_size=SIZE32; return LSR;}
-lsr\.w {LIST; inst_size=SIZE16; return LSR;}
-lsr\.b {LIST; inst_size=SIZE8; return LSR;}
-lsr {LIST; inst_size=UNKNOWN; return LSR;}
-mov\.w {LIST; inst_size=SIZE16; return MOV;}
-mov\.b {LIST; inst_size=SIZE8; return MOV;}
-mov {LIST; inst_size=UNKNOWN; return MOV;}
-movc\.w {LIST; inst_size=SIZE16; return MOVC;}
-movc\.b {LIST; inst_size=SIZE8; return MOVC;}
-movc {LIST; inst_size=UNKNOWN; return MOVC;}
-movs\.w {LIST; inst_size=SIZE16; return MOVS;}
-movs\.b {LIST; inst_size=SIZE8; return MOVS;}
-movs {LIST; inst_size=UNKNOWN; return MOVS;}
-movx\.w {LIST; inst_size=SIZE16; return MOVX;}
-movx\.b {LIST; inst_size=SIZE8; return MOVX;}
-movx {LIST; inst_size=UNKNOWN; return MOVX;}
-mul\.d {LIST; inst_size=SIZE32; return MUL;}
-mul\.w {LIST; inst_size=SIZE16; return MUL;}
-mul\.b {LIST; inst_size=SIZE8; return MUL;}
-mul {LIST; inst_size=UNKNOWN; return MUL;}
-mulu\.d {LIST; inst_size=SIZE32; return MULU;}
-mulu\.w {LIST; inst_size=SIZE16; return MULU;}
-mulu\.b {LIST; inst_size=SIZE8; return MULU;}
-mulu {LIST; inst_size=UNKNOWN; return MULU;}
-neg\.w {LIST; inst_size=SIZE16; return NEG;}
-neg\.b {LIST; inst_size=SIZE8; return NEG;}
-neg {LIST; inst_size=UNKNOWN; return NEG;}
-nop {LIST; inst_size=UNKNOWN; return NOP;}
-norm\.d {LIST; inst_size=SIZE32; return NORM;}
-norm\.w {LIST; inst_size=SIZE16; return NORM;}
-norm\.b {LIST; inst_size=SIZE8; return NORM;}
-norm {LIST; inst_size=UNKNOWN; return NORM;}
-or\.w {LIST; inst_size=SIZE16; return OR;}
-or\.b {LIST; inst_size=SIZE8; return OR;}
-or {LIST; inst_size=UNKNOWN; return OR;}
-orl {LIST; inst_size=UNKNOWN; return ORL;}
-pop\.w {LIST; inst_size=SIZE16; return POP;}
-pop\.b {LIST; inst_size=SIZE8; return POP;}
-pop {LIST; inst_size=UNKNOWN; return POP;}
-popu\.w {LIST; inst_size=SIZE16; return POPU;}
-popu\.b {LIST; inst_size=SIZE8; return POPU;}
-popu {LIST; inst_size=UNKNOWN; return POPU;}
-push\.w {LIST; inst_size=SIZE16; return PUSH;}
-push\.b {LIST; inst_size=SIZE8; return PUSH;}
-push {LIST; inst_size=UNKNOWN; return PUSH;}
-pushu\.w {LIST; inst_size=SIZE16; return PUSHU;}
-pushu\.b {LIST; inst_size=SIZE8; return PUSHU;}
-pushu {LIST; inst_size=UNKNOWN; return PUSHU;}
-reset {LIST; inst_size=UNKNOWN; return RESET;}
-ret {LIST; inst_size=UNKNOWN; return RET;}
-reti {LIST; inst_size=UNKNOWN; return RETI;}
-rl\.w {LIST; inst_size=SIZE16; return RL;}
-rl\.b {LIST; inst_size=SIZE8; return RL;}
-rl {LIST; inst_size=UNKNOWN; return RL;}
-rlc\.w {LIST; inst_size=SIZE16; return RLC;}
-rlc\.b {LIST; inst_size=SIZE8; return RLC;}
-rlc {LIST; inst_size=UNKNOWN; return RLC;}
-rr\.w {LIST; inst_size=SIZE16; return RR;}
-rr\.b {LIST; inst_size=SIZE8; return RR;}
-rr {LIST; inst_size=UNKNOWN; return RR;}
-rrc\.w {LIST; inst_size=SIZE16; return RRC;}
-rrc\.b {LIST; inst_size=SIZE8; return RRC;}
-rrc {LIST; inst_size=UNKNOWN; return RRC;}
-setb {LIST; inst_size=UNKNOWN; return SETB;}
-sext\.w {LIST; inst_size=SIZE16; return SEXT;}
-sext\.b {LIST; inst_size=SIZE8; return SEXT;}
-sext {LIST; inst_size=UNKNOWN; return SEXT;}
-sub\.w {LIST; inst_size=SIZE16; return SUB;}
-sub\.b {LIST; inst_size=SIZE8; return SUB;}
-sub {LIST; inst_size=UNKNOWN; return SUB;}
-subb\.w {LIST; inst_size=SIZE16; return SUBB;}
-subb\.b {LIST; inst_size=SIZE8; return SUBB;}
-subb {LIST; inst_size=UNKNOWN; return SUBB;}
-trap {LIST; inst_size=UNKNOWN; return TRAP;}
-xch\.w {LIST; inst_size=SIZE16; return XCH;}
-xch\.b {LIST; inst_size=SIZE8; return XCH;}
-xch {LIST; inst_size=UNKNOWN; return XCH;}
-xor\.w {LIST; inst_size=SIZE16; return XOR;}
-xor\.b {LIST; inst_size=SIZE8; return XOR;}
-xor {LIST; inst_size=UNKNOWN; return XOR;}
-
-
-dptr {LIST; return DPTR;}
-pc {LIST; return PC;}
-a {LIST; return A;}
-c {LIST; return C;}
-usp {LIST; return USP;}
-
-org {LIST; return ORG;}
-equ {LIST; return EQU;}
-sfr {LIST; return SFR;}
-db {LIST; return DB;}
-dw {LIST; return DW;}
-byte {LIST; return DB;}
-bit {LIST; return BITDEF;}
-reg {LIST; return REGDEF;}
-area {LIST; return AREA;}
-ds {LIST; return DS;}
-DSEG {LIST; yylval = AREA_DSEG; return AREA_NAME;}
-BSEG {LIST; yylval = AREA_BSEG; return AREA_NAME;}
-XSEG {LIST; yylval = AREA_XSEG; return AREA_NAME;}
-XISEG {LIST; yylval = AREA_XISEG; return AREA_NAME;}
-XINIT {LIST; yylval = AREA_XINIT; return AREA_NAME;}
-GSINIT {LIST; yylval = AREA_GSINIT; return AREA_NAME;}
-GSFINAL {LIST; yylval = AREA_GSFINAL; return AREA_NAME;}
-HOME {LIST; yylval = AREA_HOME; return AREA_NAME;}
-SSEG {LIST; yylval = AREA_SSEG; return AREA_NAME;}
-CSEG {LIST; yylval = AREA_CSEG; return AREA_NAME;}
-module {LIST; return MODULE;}
-globl {LIST; return GLOBL;}
-\(DATA\) {LIST; return AREA_DESC;}
-\(OVR,XDATA\) {LIST; return AREA_DESC;}
-\(BIT\) {LIST; return AREA_DESC;}
-\(XDATA\) {LIST; return AREA_DESC;}
-\(CODE\) {LIST; return AREA_DESC;}
-low {LIST; return LOW;}
-high {LIST; return HIGH;}
->> {LIST; return RSHIFT;}
-\<\< {LIST; return LSHIFT;}
-
-
-R[0-9] {LIST; yylval = yytext[1] - '0' + WORD_REG; return REG;}
-R1[0-5] {LIST; yylval = yytext[2] - '0' + 10 + WORD_REG; return REG;}
-R[0-7]L {LIST; yylval = (yytext[1] - '0') * 2 + BYTE_REG; return REG;}
-R[0-7]H {LIST; yylval = (yytext[1] - '0') * 2 + 1 + BYTE_REG; return REG;}
-
-
-[a-z_][a-z0-9_]* {
- LIST;
- if (is_def(yytext)) {
- yylval = get_value(yytext);
- } else {
- yylval = 0;
- if (p3) error("Symbol undefined");
- }
- /* keep name in lex_sym_name since yytext */
- /* could be overwritten if the parser does */
- /* a lookahead operation */
- strcpy(lex_sym_name, yytext);
- if (is_def(lex_sym_name)) {
- yylval = get_value(lex_sym_name);
- /* return correct type if special */
- if (is_bit(lex_sym_name)) return BIT;
- if (is_reg(lex_sym_name)) return REG;
- }
- return WORD;
- }
-[0-9]+\$ {
- LIST;
- /* should print error if base_symbol_name */
- /* is not defined */
- sprintf(lex_sym_name, "%s:%s",
- base_symbol_name, yytext);
- if (is_def(lex_sym_name)) {
- yylval = get_value(lex_sym_name);
- } else {
- yylval = 0;
- if (p3) error("Symbol undefined");
- }
- return WORD;
- }
-[01]+[bq] {
- LIST;
- yylval = binary2int(yytext);
- return NUMBER;
- }
-0x[0-9a-f]+ {
- LIST;
- sscanf(yytext, "%*c%*c%x", &yylval);
- return NUMBER;
- }
-[0-9a-f]+[h] {
- LIST;
- sscanf(yytext, "%x%*[hH]", &yylval);
- return NUMBER;
- }
-\$[0-9a-f]+ {
- LIST;
- sscanf(yytext, "$%x", &yylval);
- return NUMBER;
- }
--?[0-9]+ {
- LIST;
- sscanf(yytext, "%d", &yylval);
- return NUMBER;
- }
-\'.\' {
- LIST;
- yylval = (int)yytext[1];
- return CHAR;
- }
-\'\\.\' {
- LIST;
- switch (yytext[1]) {
- case 'n':
- case 'N': yylval = 10; break;
- case 'r':
- case 'R': yylval = 13; break;
- case '0': yylval = 0; break;
- default: yylval = (int)yytext[1];
- /* print a warning here */
- }
- return CHAR;
- }
-\"[^"\n]*["\n] {
- LIST;
- return STRING;
- }
-
-;[^\n]* {LIST; /* comments */}
-[ \t\r] {LIST; /* whitespace */}
-
-\n {
- strcpy(last_line_text, line_text);
- line_text[0] = '\0';
- ++lineno;
- return EOL;
- }
-
-. {LIST; return yytext[0];}
-
-%%
+++ /dev/null
-%{
-/* This file is part of Paul's XA51 Assembler, Copyright 1997,2002 Paul Stoffregen
- *
- * Paul's XA51 Assembler is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2.
- *
- * Paul's XA51 Assembler is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* Author contact: paul@pjrc.com */
-
-/* parser for the 51-XA assembler, Paul Stoffregen, July 1997 */
-#include <stdio.h>
-
-#include "xa_main.h"
-
-int op[MAX_DB];
-int size;
-int inst_size;
-int arith_opcode, short_opcode, num_op, opcode0, opcode1;
-int shift_imm_opcode, shift_reg_opcode, rotate_opcode;
-int stack_addr_opcode, stack_reg_opcode, branch_opcode;
-int rlist_reg_bank, rlist_bitmask, rlist_size;
-int db_count, dw_count, i;
-char symbol_name[MAX_SYMBOL], base_symbol_name[MAX_SYMBOL]={'\0'};
-char expr_var[MAX_SYMBOL]={0,0,0,'\0'};
-
-extern char lex_sym_name[];
-extern int yylex();
-
-extern void yyrestart(FILE *new_file);
-extern char * disasm(int byte, int memory_location);
-extern void hexout(int byte, int memory_location, int end);
-void error(char *s);
-
-static int bitmask[]={1, 2, 4, 8, 16, 32, 64, 128};
-
-%}
-
-%token ADD ADDC ADDS AND ANL ASL ASR BCC BCS BEQ BG BGE BGT
-%token BKPT BL BLE BLT BMI BNE BNV BOV BPL BR CALL CJNE CLR
-%token CMP CPL DA DIV DIVU DJNZ FCALL FJMP JB JBC JMP JNB JNZ
-%token JZ LEA LSR MOV MOVC MOVS MOVX MUL MULU NEG NOP NORM
-%token OR ORL POP POPU PUSH PUSHU RESET RET RETI RL RLC RR RRC
-%token SETB SEXT SUB SUBB TRAP XCH XOR
-%token REG DPTR PC A C USP
-%token WORD BIT NUMBER CHAR STRING EOL LOCAL_LABEL
-%token ORG EQU SFR DB DW BITDEF REGDEF LOW HIGH
-%token RSHIFT LSHIFT
-%token AREA AREA_NAME AREA_DESC DS
-%token MODULE GLOBL
-
-%left '&' '|' '^'
-%left RSHIFT LSHIFT
-%left '+' '-'
-%left '*' '/'
-%nonassoc UNARY
-
-%%
-
-all: line
- | line all;
-
-line: linesymbol ':' linenosym {
- if (p1) {
- build_sym_list(symbol_name);
- if (current_area == AREA_BSEG) {
- mk_bit(symbol_name);
- }
- }
- if (p1 || p2) assign_value(symbol_name, MEM_POS);
- MEM_POS += $3;
- }
- | linenosym {
- MEM_POS += $1;
- }
-
-linenosym: directive EOL {
- if (p3) out(op, $1);
- $$ = $1;
- }
- | instruction EOL {
- if (p3) out(op, $1);
- $$ = $1;
- }
- | EOL {
- if (p3) out(NULL, 0);
- $$ = 0;
- }
- | error EOL /* try to recover from any parse error */
-
-
-directive: '.' ORG expr {
- MEM_POS = $3;
- $$ = 0;
- }
- | ORG expr {
- MEM_POS = $2;
- $$ = 0;
- }
- | '.' EQU symbol ',' expr {
- if (p1) build_sym_list(symbol_name);
- if (p1 || p2) assign_value(symbol_name, $5);
- $$ = 0;
- }
- | normal_or_bit_symbol '=' expr {
- if (p1) build_sym_list(symbol_name);
- if (p1 || p2) assign_value(symbol_name, $3);
- }
- | symbol SFR expr {
- if (p1) build_sym_list(symbol_name);
- if (p1 || p2) assign_value(symbol_name, $3);
- if (p1 || p2) mk_sfr(symbol_name);
- $$ = 0;
- }
- | '.' BITDEF bitsymbol ',' bit {
- if (p1) {
- build_sym_list(symbol_name);
- mk_bit(symbol_name);
- }
- if (p1 || p2) assign_value(symbol_name, $5);
- $$ = 0;
- }
- | bitsymbol BITDEF bit {
- if (p1) {
- build_sym_list(symbol_name);
- mk_bit(symbol_name);
- }
- if (p1 || p2) assign_value(symbol_name, $3);
- $$ = 0;
- }
- | bitsymbol BITDEF expr {
- if (p1) {
- build_sym_list(symbol_name);
- mk_bit(symbol_name);
- }
- if (p1 || p2) assign_value(symbol_name, $3);
- $$ = 0;
- }
- | '.' REGDEF regsymbol ',' REG {
- if (p1) {
- build_sym_list(symbol_name);
- mk_reg(symbol_name);
- }
- if (p1 || p2) assign_value(symbol_name, $5);
- $$ = 0;
- }
- | regsymbol REGDEF REG {
- if (p1) {
- build_sym_list(symbol_name);
- mk_reg(symbol_name);
- }
- if (p1 || p2) assign_value(symbol_name, $3);
- $$ = 0;
- }
-
- | '.' db_directive bytes {
- $$ = db_count;
- }
- | '.' dw_directive words {
- $$ = dw_count;
- }
- | '.' AREA AREA_NAME AREA_DESC {
- if ($3 < 0 || $3 >= NUM_AREAS) {
- error("Illegal Area Directive");
- }
- symbol_name[0] = '\0';
- current_area = $3;
- $$ = 0;
- }
- | '.' MODULE WORD {
- /* ignore module definition */
- $$ = 0;
- }
- | '.' GLOBL WORD {
- /* ignore global symbol declaration */
- $$ = 0;
- }
- | '.' GLOBL bit {
- /* ignore bit symbol declaration */
- $$ = 0;
- }
- | '.' DS expr {
- /* todo: if CSEG, emit some filler bytes */
- $$ = $3;
- }
-
-db_directive: DB {db_count = 0;}
-
-
-linesymbol: normal_or_bit_symbol {
- strcpy(symbol_name, lex_sym_name);
- if (!strchr(lex_sym_name, ':')) {
- /* non-local label, remember base name */
- strcpy(base_symbol_name, lex_sym_name);
- }
- if (is_target(symbol_name)) pad_with_nop();
- }
-
-normal_or_bit_symbol: WORD {$$ = $1;}
- | BIT {$$ = $1;}
-
-bytes: byte_element
- | bytes ',' byte_element
-
-byte_element: expr {
- op[db_count] = $1 & 255;
- if (++db_count >= MAX_DB) {
- error("too many bytes, use two DB");
- db_count--;
- }
- }
- | STRING {
- for(i=1; i < strlen(yytext)-1; i++) {
- op[db_count++] = yytext[i];
- if (db_count >= MAX_DB) {
- error("too many bytes, use two DB");
- db_count--;
- }
- }
- }
-
-dw_directive: DW {dw_count = 0;}
-
-words: words ',' word_element
- | word_element
-
-word_element: expr {
- op[dw_count] = $1 & 255;
- op[dw_count+1] = ($1 >> 8) & 255;
- dw_count += 2;
- if (dw_count >= MAX_DB) {
- error("too many bytes, use two DW");
- db_count -= 2;
- }
- }
-
-
-
-symbol: WORD {
- strcpy(symbol_name, lex_sym_name);
- }
-
-bitsymbol: WORD { strcpy(symbol_name, lex_sym_name); }
- | BIT { strcpy(symbol_name, lex_sym_name); }
-
-
-regsymbol: WORD { strcpy(symbol_name, lex_sym_name); }
- | REG { strcpy(symbol_name, lex_sym_name); }
-
-bit: expr '.' expr {
- if ($3 < 0 || $3 > 7) {
- /* only 8 bits in a byte */
- error("Only eight bits in a byte");
- }
- $$ = 100000; /* should really check $1 is valid */
- if ($1 >= 0x20 && $1 <= 0x3F) {
- $$ = $1 * 8 + $3;
- }
- if ($1 >= 0x400 && $1 <= 0x43F) {
- $$ = ($1 - 0x400) * 8 + $3 + 0x200;
- }
- }
- | REG '.' expr {
- $$ = 100000;
- if (find_size_reg($1) == SIZE8) {
- if ($3 < 0 || $3 > 7)
- error("byte reg has only 8 bits");
- $$ = reg($1) * 8 + $3;
- }
- if (find_size_reg($1) == SIZE16) {
- if ($3 < 0 || $3 > 15)
- error("word reg has only 16 bits");
- $$ = reg($1) * 16 + $3;
- }
- }
- | BIT {$$ = $1;}
-
-jmpaddr: WORD {
- $$ = $1;
- if (p1) build_target_list(lex_sym_name);
- }
- | NUMBER {
- if ($1 & 1) error("Jump target must be aligned");
- $$ = $1;
- }
-
-
-expr: value {$$ = $1;}
- | expr '+' expr {$$ = $1 + $3;}
- | expr '-' expr {$$ = $1 - $3;}
- | expr '*' expr {$$ = $1 * $3;}
- | expr '/' expr {$$ = $1 / $3;}
- | expr '&' expr {$$ = $1 & $3;}
- | expr '|' expr {$$ = $1 | $3;}
- | expr '^' expr {$$ = $1 ^ $3;}
- | expr RSHIFT expr {$$ = $1 >> $3;}
- | expr LSHIFT expr {$$ = $1 << $3;}
- | '-' expr %prec UNARY {$$ = $2 * -1;}
- | '+' expr %prec UNARY {$$ = $2;}
- | '(' expr ')' {$$ = $2;}
- | LOW expr %prec UNARY {$$ = $2 & 255;}
- | HIGH expr %prec UNARY {$$ = ($2 >> 8) & 255;}
-
-
-value: NUMBER {$$ = $1;}
- | CHAR {$$ = $1;}
- | WORD {$$ = $1; strcpy(expr_var, yytext);}
-
-
-rlist: REG {
- rlist_bitmask = bitmask[reg($1) % 8];
- rlist_reg_bank = (reg($1) / 8) ? 1 : 0;
- rlist_size = find_size_reg($1);
- }
- | REG ',' rlist {
- rlist_bitmask |= bitmask[reg($1) % 8];
- if (rlist_reg_bank != ((reg($1) / 8) ? 1 : 0))
- error("register list may not mix 0-7/8-15 regs");
- if (rlist_size != find_size_reg($1))
- error("register list may not mix 8/16 bit registers");
- }
-
-
-
-
-
-instruction:
-
- arith_inst REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- op[0] = arith_opcode * 16 + size * 8 + 1;
- op[1] = reg($2) * 16 + reg($4);
- }
-| arith_inst REG ',' '[' REG ']' {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = arith_opcode * 16 + size * 8 + 2;
- op[1] = reg($2) * 16 + reg_indirect($5);
- }
-| arith_inst '[' REG ']' ',' REG {
- $$ = 2;
- size = find_size1(inst_size, $6);
- op[0] = arith_opcode * 16 + size * 8 + 2;
- op[1] = reg($6) * 16 + 8 + reg_indirect($3);
- }
-| arith_inst REG ',' '[' REG '+' expr ']' {
- size = find_size1(inst_size, $2);
- if ($7 >= -128 && $7 <= 127) {
- $$ = 3;
- op[0] = arith_opcode * 16 + size * 8 + 4;
- op[1] = reg($2) * 16 + reg_indirect($5);
- op[2] = ($7 >= 0) ? $7 : 256 + $7;
- } else {
- $$ = 4;
- op[0] = arith_opcode * 16 + size * 8 + 5;
- op[1] = reg($2) * 16 + reg_indirect($5);
- op[2] = ($7 >= 0) ? msb($7) : msb(65536 + $7);
- op[3] = ($7 >= 0) ? lsb($7) : lsb(65536 + $7);
- }
- }
-| arith_inst '[' REG '+' expr ']' ',' REG {
- size = find_size1(inst_size, $8);
- if ($5 >= -128 && $5 <= 127) {
- $$ = 3;
- op[0] = arith_opcode * 16 + size * 8 + 4;
- op[1] = reg($8) * 16 + 8 + reg_indirect($3);
- op[2] = ($5 >= 0) ? $5 : 256 + $5;
- } else {
- $$ = 4;
- op[0] = arith_opcode * 16 + size * 8 + 5;
- op[1] = reg($8) * 16 + 8 + reg_indirect($3);
- op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
- op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
- }
- }
-| arith_inst REG ',' '[' REG '+' ']' {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = arith_opcode * 16 + size * 8 + 3;
- op[1] = reg($2) * 16 + reg_indirect($5);
- }
-| arith_inst '[' REG '+' ']' ',' REG {
- $$ = 2;
- size = find_size1(inst_size, $7);
- op[0] = arith_opcode * 16 + size * 8 + 3;
- op[1] = reg($7) * 16 + 8 + reg_indirect($3);
- }
-| arith_inst expr ',' REG {
- $$ = 3;
- size = find_size1(inst_size, $4);
- op[0] = arith_opcode * 16 + size * 8 + 6;
- op[1] = reg($4) * 16 + 8 + msb(direct_addr($2));
- op[2] = lsb(direct_addr($2));
- }
-| arith_inst REG ',' expr {
- $$ = 3;
- size = find_size1(inst_size, $2);
- op[0] = arith_opcode * 16 + size * 8 + 6;
- op[1] = reg($2) * 16 + msb(direct_addr($4));
- op[2] = lsb(direct_addr($4));
- }
-| arith_inst REG ',' '#' expr {
- size = find_size1(inst_size, $2);
- if (size == SIZE8) {
- $$ = 3;
- op[0] = 0x91;
- op[1] = reg($2) * 16 + arith_opcode;
- op[2] = imm_data8($5);
- } else {
- $$ = 4;
- op[0] = 0x99;
- op[1] = reg($2) * 16 + arith_opcode;
- op[2] = msb(imm_data16($5));
- op[3] = lsb(imm_data16($5));
- }
- }
-| arith_inst '[' REG ']' ',' '#' expr {
- size = find_size0(inst_size);
- if (size == SIZE8) {
- $$ = 3;
- op[0] = 0x92;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = imm_data8($7);
- } else {
- $$ = 4;
- op[0] = 0x9A;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = msb(imm_data16($7));
- op[3] = lsb(imm_data16($7));
- }
- }
-| arith_inst '[' REG '+' ']' ',' '#' expr {
- size = find_size0(inst_size);
- if (size == SIZE8) {
- $$ = 3;
- op[0] = 0x93;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = imm_data8($8);
- } else {
- $$ = 4;
- op[0] = 0x9B;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = msb(imm_data16($8));
- op[3] = lsb(imm_data16($8));
- }
- }
-| arith_inst '[' REG '+' expr ']' ',' '#' expr {
- size = find_size0(inst_size);
- if ($5 >= -128 && $5 <= 127) {
- if (size == SIZE8) {
- $$ = 4;
- op[0] = 0x94;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = ($5 >= 0) ? $5 : 256 + $5;
- op[3] = imm_data8($9);
- } else {
- $$ = 5;
- op[0] = 0x9C;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = ($5 >= 0) ? $5 : 256 + $5;
- op[3] = msb(imm_data16($9));
- op[4] = lsb(imm_data16($9));
- }
- } else {
- if (size == SIZE8) {
- $$ = 5;
- op[0] = 0x95;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
- op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
- op[4] = imm_data8($9);
- } else {
- $$ = 6;
- op[0] = 0x9D;
- op[1] = reg_indirect($3) * 16 + arith_opcode;
- op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
- op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
- op[4] = msb(imm_data16($9));
- op[5] = lsb(imm_data16($9));
- }
- }
- }
-| arith_inst expr ',' '#' expr {
- size = find_size0(inst_size);
- if (size == SIZE8) {
- $$ = 4;
- op[0] = 0x96;
- op[1] = msb(direct_addr($2)) * 16 + arith_opcode;
- op[2] = lsb(direct_addr($2));
- op[3] = imm_data8($5);
- } else {
- $$ = 5;
- op[0] = 0x9E;
- op[1] = msb(direct_addr($2)) * 16 + arith_opcode;
- op[2] = lsb(direct_addr($2));
- op[3] = msb(imm_data16($5));
- op[4] = lsb(imm_data16($5));
- }
- }
-
-/* the next 8 instructions are MOV, but because MOV was used in the */
-/* arith_inst group, it will cause a shift/reduce conflict if used */
-/* directly below... so we're forced to use arith_inst and then */
-/* add a bit of code to make sure it was MOV and not the other ones */
-
-| arith_inst '[' REG '+' ']' ',' '[' REG '+' ']' {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (1)");
- size = find_size0(inst_size);
- $$ = 2;
- op[0] = 0x90 + size * 8;
- op[1] = reg_indirect($3) * 16 + reg_indirect($8);
- }
-| arith_inst expr ',' '[' REG ']' {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (2)");
- size = find_size0(inst_size);
- $$ = 3;
- op[0] = 0xA0 + size * 8;
- op[1] = 128 + reg_indirect($5) * 16 + msb(direct_addr($2));
- op[2] = lsb(direct_addr($2));
- }
-| arith_inst '[' REG ']' ',' expr {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (3)");
- size = find_size0(inst_size);
- $$ = 3;
- op[0] = 0xA0 + size * 8;
- op[1] = reg_indirect($3) * 16 + msb(direct_addr($6));
- op[2] = lsb(direct_addr($6));
- }
-| arith_inst expr ',' expr {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (4)");
- size = find_size0(inst_size);
- $$ = 4;
- op[0] = 0x97 + size * 8;
- op[1] = msb(direct_addr($2)) * 16 + msb(direct_addr($4));
- op[2] = lsb(direct_addr($2));
- op[3] = lsb(direct_addr($4));
- }
-| arith_inst REG ',' USP {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (5)");
- $$ = 2;
- op[0] = 0x90;
- op[1] = reg($2) * 16 + 15;
- }
-| arith_inst USP ',' REG {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (6)");
- $$ = 2;
- op[0] = 0x98;
- op[1] = reg($4) * 16 + 15;
- }
-| arith_inst C ',' bit {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (7)");
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x20 + msb(bit_addr($4));
- op[2] = lsb(bit_addr($4));
- }
-| arith_inst bit ',' C {
- /* this addr mode is only valid for MOV */
- if (arith_opcode != 8) error("Addr mode only valid for MOV (8)");
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x30 + msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- }
-
-| MOVC REG ',' '[' REG '+' ']' {
- size = find_size1(inst_size, $2);
- $$ = 2;
- op[0] = 0x80 + size * 8;
- op[1] = reg($2) * 16 + reg_indirect($5);
- }
-| MOVC A ',' '[' A '+' DPTR ']' {
- $$ = 2;
- op[0] = 0x90;
- op[1] = 0x4E;
- }
-| MOVC A ',' '[' A '+' PC ']' {
- $$ = 2;
- op[0] = 0x90;
- op[1] = 0x4C;
- }
-| MOVX REG ',' '[' REG ']' {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0xA7 + size * 8;
- op[1] = reg($2) * 16 + reg_indirect($5);
- }
-| MOVX '[' REG ']' ',' REG {
- $$ = 2;
- size = find_size1(inst_size, $6);
- op[0] = 0xA7 + size * 8;
- op[1] = reg($6) * 16 + 8 + reg_indirect($3);
- }
-| XCH REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- op[0] = 0x60 + size * 8;
- op[1] = reg($2) * 16 + reg($4);
- }
-| XCH REG ',' '[' REG ']' {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0x50 + size * 8;
- op[1] = reg($2) * 16 + reg_indirect($5);
- }
-| XCH REG ',' expr {
- $$ = 3;
- size = find_size1(inst_size, $2);
- op[0] = 0xA0 + size * 8;
- op[1] = reg($2) * 16 + msb(direct_addr($4));
- op[2] = lsb(direct_addr($4));
- }
-| short_data_inst REG ',' '#' expr {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = short_opcode + size * 8 + 1;
- op[1] = reg($2) * 16 + imm_data4_signed($5);
- }
-| short_data_inst '[' REG ']' ',' '#' expr {
- $$ = 2;
- size = find_size0(inst_size);
- op[0] = short_opcode + size * 8 + 2;
- op[1] = reg_indirect($3) * 16 + imm_data4_signed($7);
- }
-| short_data_inst '[' REG '+' ']' ',' '#' expr {
- $$ = 2;
- size = find_size0(inst_size);
- op[0] = short_opcode + size * 8 + 3;
- op[1] = reg_indirect($3) * 16 + imm_data4_signed($8);
- }
-| short_data_inst '[' REG '+' expr ']' ',' '#' expr {
- size = find_size0(inst_size);
- if ($5 >= -128 && $5 <= 127) {
- $$ = 3;
- op[0] = short_opcode + size * 8 + 4;
- op[1] = reg_indirect($3) * 16 + imm_data4_signed($9);
- op[2] = op[2] = ($5 >= 0) ? $5 : 256 + $5;
- } else {
- $$ = 4;
- op[0] = short_opcode + size * 8 + 5;
- op[1] = reg_indirect($3) * 16 + imm_data4_signed($9);
- op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
- op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
- }
- }
-| short_data_inst expr ',' '#' expr {
- $$ = 3;
- size = find_size0(inst_size);
- op[0] = short_opcode + size * 8 + 6;
- op[1] = msb(direct_addr($2)) * 16 + imm_data4_signed($5);
- op[2] = lsb(direct_addr($2));
- }
-
-
-
-| ANL C ',' bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x40 + msb(bit_addr($4));
- op[2] = lsb(bit_addr($4));
- }
-| ANL C ',' '/' bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x50 + msb(bit_addr($5));
- op[2] = lsb(bit_addr($5));
- }
-
-| ORL C ',' bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x60 + msb(bit_addr($4));
- op[2] = lsb(bit_addr($4));
- }
-| ORL C ',' '/' bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x70 + msb(bit_addr($5));
- op[2] = lsb(bit_addr($5));
- }
-| CLR bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- }
-| SETB bit {
- $$ = 3;
- op[0] = 0x08;
- op[1] = 0x10 + msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- }
-| logical_shift_inst REG ',' REG {
- size = find_size1(inst_size, $2);
- if (find_size_reg($4) != SIZE8)
- error("Second register in logical shift must be byte size");
- $$ = 2;
- op[0] = shift_reg_opcode;
- switch (size) {
- case SIZE8: op[0] += 0; break;
- case SIZE16: op[0] += 8; break;
- case SIZE32: op[0] += 12; break;
- }
- op[1] = reg($2) * 16 + reg($4);
- }
-| logical_shift_inst REG ',' '#' expr {
- size = find_size1(inst_size, $2);
- $$ = 2;
- if (shift_imm_opcode == -1)
- error("NORM may not use a constant");
- op[0] = shift_imm_opcode;
- switch (size) {
- case SIZE8: op[0] += 0; break;
- case SIZE16: op[0] += 8; break;
- case SIZE32: op[0] += 12; break;
- }
- switch (size) {
- case SIZE8:
- case SIZE16:
- op[1] = reg($2) * 16 + imm_data4_unsigned($5);
- break;
- case SIZE32:
- op[1] = (reg($2) / 2) * 32 + imm_data5_unsigned($5);
- break;
- }
- }
-| no_opperand_inst {
- $$ = num_op;
- op[0] = opcode0;
- op[1] = opcode1;
- }
-
-| TRAP '#' expr {
- $$ = 2;
- op[0] = 0xD6;
- op[1] = 0x30 + imm_data4_unsigned($3);
- }
-| CPL REG {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0x90 + size * 8;
- op[1] = reg($2) * 16 + 10;
- }
-| DA REG {
- $$ = 2;
- op[0] = 0x90;
- op[1] = reg($2) * 16 + 8;
- }
-| NEG REG {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0x90 + size * 8;
- op[1] = reg($2) * 16 + 11;
- }
-| SEXT REG {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0x90 + size * 8;
- op[1] = reg($2) * 16 + 9;
- }
-
-| rotate_inst REG ',' '#' expr {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = rotate_opcode + size * 8;
- op[1] = reg($2) * 16 + imm_data4_unsigned($5);
- }
-
-
-| LEA REG ',' REG '+' expr {
- if ($6 >= -128 && $6 <= 127) {
- $$ = 3;
- op[0] = 0x40;
- op[1] = reg($2) * 16 + reg_indirect($4);
- op[2] = ($6 >= 0) ? $6 : 256 + $6;
- } else {
- op[0] = 0x48;
- op[1] = reg($2) * 16 + reg_indirect($4);
- op[2] = ($6 >= 0) ? msb($6) : msb(65536 + $6);
- op[3] = ($6 >= 0) ? lsb($6) : lsb(65536 + $6);
- }
- }
-| stack_inst expr {
- $$ = 3;
- size = find_size0(inst_size);
- op[0] = msb(stack_addr_opcode) + size * 8;
- op[1] = lsb(stack_addr_opcode) + msb(direct_addr($2));
- op[2] = lsb(direct_addr($2));
- }
-| stack_inst rlist {
- $$ = 2;
- if (inst_size != UNKNOWN && find_size0(inst_size) != rlist_size)
- error("inst specifies different size than registers used");
- op[0] = stack_reg_opcode + rlist_reg_bank * 64 + rlist_size * 8;
- op[1] = rlist_bitmask;
- }
-
-
-| MUL REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- op[0] = 0xE6;
- op[1] = reg($2) * 16 + reg($4);
- }
-| MULU REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- if (size == SIZE8) {
- op[0] = 0xE0;
- op[1] = reg($2) * 16 + reg($4);
- } else {
- op[0] = 0xE4;
- op[1] = reg($2) * 16 + reg($4);
- }
- }
-| MUL REG ',' '#' expr {
- $$ = 2;
- size = find_size1(inst_size, $2);
- op[0] = 0xE9;
- op[1] = reg($2) + 8;
- op[2] = msb(imm_data16($5));
- op[3] = lsb(imm_data16($5));
- }
-| MULU REG ',' '#' expr {
- size = find_size2(inst_size, $2, $4);
- if (size == SIZE8) {
- $$ = 3;
- op[0] = 0xE8;
- op[1] = reg($2) * 16;
- op[2] = imm_data8($5);
- } else {
- $$ = 4;
- op[0] = 0xE9;
- op[1] = reg($2) * 16;
- op[2] = msb(imm_data16($5));
- op[3] = lsb(imm_data16($5));
- }
- }
-| DIV REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- switch (size) {
- case SIZE8:
- error("Singed DIV can't be 8 bit size"); break;
- case SIZE16:
- op[0] = 0xE7;
- op[1] = reg($2) * 16 + reg($4);
- break;
- case SIZE32:
- op[0] = 0xEF;
- op[1] = (reg($2) / 2) * 32 + reg($4);
- break;
- }
- }
-| DIVU REG ',' REG {
- $$ = 2;
- size = find_size2(inst_size, $2, $4);
- switch (size) {
- case SIZE8:
- op[0] = 0xE1;
- op[1] = reg($2) * 16 + reg($4);
- break;
- case SIZE16:
- op[0] = 0xE5;
- op[1] = reg($2) * 16 + reg($4);
- break;
- case SIZE32:
- op[0] = 0xED;
- op[1] = (reg($2) / 2) * 32 + reg($4);
- break;
- }
- }
-| DIV REG ',' '#' expr {
- size = find_size1(inst_size, $2);
- switch (size) {
- case SIZE8:
- error("Singed DIV can't be 8 bit size"); break;
- case SIZE16:
- $$ = 3;
- op[0] = 0xE8;
- op[1] = reg($2) * 16 + 11;
- op[2] = imm_data8($5);
- break;
- case SIZE32:
- $$ = 4;
- op[0] = 0xE9;
- op[1] = (reg($2) / 2) * 32 + 9;
- op[2] = msb(imm_data16($5));
- op[3] = lsb(imm_data16($5));
- break;
- }
- }
-| DIVU REG ',' '#' expr {
- size = find_size1(inst_size, $2);
- switch (size) {
- case SIZE8:
- $$ = 3;
- op[0] = 0xE8;
- op[1] = reg($2) * 16 + 1;
- op[2] = imm_data8($5);
- break;
- case SIZE16:
- $$ = 3;
- op[0] = 0xE8;
- op[1] = reg($2) * 16 + 3;
- op[2] = imm_data8($5);
- break;
- case SIZE32:
- $$ = 4;
- op[0] = 0xE9;
- op[1] = (reg($2) / 2) * 32 + 1;
- op[2] = msb(imm_data16($5));
- op[3] = lsb(imm_data16($5));
- break;
- }
- }
-| CALL '[' REG ']' {
- $$ = 2;
- op[0] = 0xC6;
- op[1] = reg($3);
- }
-| FCALL jmpaddr {
- $$ = 4;
- op[0] = 0xC4;
- op[1] = ($2 >> 8) & 255;
- op[2] = $2 & 255;
- op[3] = ($2 >> 16) & 255;
- }
-| FJMP jmpaddr {
- $$ = 4;
- op[0] = 0xD4;
- op[1] = ($2 >> 8) & 255;
- op[2] = $2 & 255;
- op[3] = ($2 >> 16) & 255;
- }
-| JMP '[' REG ']' {
- $$ = 2;
- op[0] = 0xD6;
- op[1] = 0x70 + reg_indirect($3);
- }
-| JMP '[' A '+' DPTR ']' {
- $$ = 2;
- op[0] = 0xD6;
- op[1] = 0x46;
- }
-| JMP '[' '[' REG '+' ']' ']' {
- $$ = 2;
- op[0] = 0xD6;
- op[1] = 0x60 + reg_indirect($4);
- }
-
-| JMP jmpaddr {
- $$ = 3;
- op[0] = 0xD5;
- op[1] = msb(rel16(MEM_POS + $$, $2));
- op[2] = lsb(rel16(MEM_POS + $$, $2));
- }
-
-| CALL jmpaddr {
- $$ = 3;
- op[0] = 0xC5;
- op[1] = msb(rel16(MEM_POS + $$, $2));
- op[2] = lsb(rel16(MEM_POS + $$, $2));
- }
-| branch_inst jmpaddr {
- $$ = 2;
- op[0] = branch_opcode;
- op[1] = rel8(MEM_POS + $$, $2);
- }
-| CJNE REG ',' expr ',' jmpaddr {
- $$ = 4;
- size = find_size1(inst_size, $2);
- op[0] = 0xE2 + size * 8;
- op[1] = reg($2) * 16 + msb(direct_addr($4));
- op[2] = lsb(direct_addr($4));
- op[3] = rel8(MEM_POS + $$, $6);
- }
-| CJNE REG ',' '#' expr ',' jmpaddr {
- size = find_size1(inst_size, $2);
- if (size == SIZE8) {
- $$ = 4;
- op[0] = 0xE3;
- op[1] = reg($2) * 16;
- op[2] = rel8(MEM_POS + $$, $7);
- op[3] = imm_data8($5);
- } else {
- $$ = 5;
- op[0] = 0xEB;
- op[1] = reg($2) * 16;
- op[2] = rel8(MEM_POS + $$, $7);
- op[3] = msb(imm_data16($5));
- op[4] = lsb(imm_data16($5));
- }
- }
-| CJNE '[' REG ']' ',' '#' expr ',' jmpaddr {
- size = find_size0(inst_size);
- if (size == SIZE8) {
- $$ = 4;
- op[0] = 0xE3;
- op[1] = reg_indirect($3) * 16 + 8;
- op[2] = rel8(MEM_POS + $$, $9);
- op[3] = imm_data8($7);
- } else {
- $$ = 5;
- op[0] = 0xEB;
- op[1] = reg_indirect($3) * 16 + 8;
- op[2] = rel8(MEM_POS + $$, $9);
- op[3] = msb(imm_data16($7));
- op[4] = lsb(imm_data16($7));
- }
- }
-| DJNZ REG ',' jmpaddr {
- $$ = 3;
- size = find_size1(inst_size, $2);
- op[0] = 0x87 + size * 8;
- op[1] = reg($2) * 16 + 8;
- op[2] = rel8(MEM_POS + $$, $4);
- }
-
-
-| DJNZ expr ',' jmpaddr {
- $$ = 4;
- size = find_size0(inst_size);
- op[0] = 0xE2 + size * 8;
- op[1] = msb(direct_addr($2)) + 8;
- op[2] = lsb(direct_addr($2));
- op[3] = rel8(MEM_POS + $$, $4);
- }
-
-| JB bit ',' jmpaddr {
- $$ = 4;
- op[0] = 0x97;
- op[1] = 0x80 + msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- op[3] = rel8(MEM_POS + $$, $4);
- }
-
-| JBC bit ',' jmpaddr {
- $$ = 4;
- op[0] = 0x97;
- op[1] = 0xC0 + msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- op[3] = rel8(MEM_POS + $$, $4);
- }
-
-| JNB bit ',' jmpaddr {
- $$ = 4;
- op[0] = 0x97;
- op[1] = 0xA0 + msb(bit_addr($2));
- op[2] = lsb(bit_addr($2));
- op[3] = rel8(MEM_POS + $$, $4);
- }
-
-
-arith_inst:
- ADD {arith_opcode = 0;}
- | ADDC {arith_opcode = 1;}
- | AND {arith_opcode = 5;}
- | CMP {arith_opcode = 4;}
- | MOV {arith_opcode = 8;}
- | OR {arith_opcode = 6;}
- | SUB {arith_opcode = 2;}
- | SUBB {arith_opcode = 3;}
- | XOR {arith_opcode = 7;}
-
-short_data_inst:
- ADDS {short_opcode = 0xA0;}
- | MOVS {short_opcode = 0xB0;}
-
-logical_shift_inst:
- ASL {shift_reg_opcode = 0xC1; shift_imm_opcode = 0xD1;}
- | ASR {shift_reg_opcode = 0xC2; shift_imm_opcode = 0xD2;}
- | LSR {shift_reg_opcode = 0xC0; shift_imm_opcode = 0xD0;}
- | NORM {shift_reg_opcode = 0xC3; shift_imm_opcode = -1;}
-
-rotate_inst:
- RL {rotate_opcode = 0xD3;}
- | RLC {rotate_opcode = 0xD7;}
- | RR {rotate_opcode = 0xD0;}
- | RRC {rotate_opcode = 0xD7;}
-
-stack_inst:
- POP {stack_addr_opcode = 0x8710; stack_reg_opcode = 0x27;}
- | POPU {stack_addr_opcode = 0x8700; stack_reg_opcode = 0x37;}
- | PUSH {stack_addr_opcode = 0x8730; stack_reg_opcode = 0x07;}
- | PUSHU {stack_addr_opcode = 0x8720; stack_reg_opcode = 0x17;}
-
-no_opperand_inst:
- BKPT {num_op = 1; opcode0 = 255; opcode1 = 0;}
- | NOP {num_op = 1; opcode0 = 0; opcode1 = 0;}
- | RESET {num_op = 2; opcode0 = 0xD6; opcode1 = 0x10;}
- | RET {num_op = 2; opcode0 = 0xD6; opcode1 = 0x80;}
- | RETI {num_op = 2; opcode0 = 0xD6; opcode1 = 0x90;}
-
-branch_inst:
- BCC {branch_opcode = 0xF0;}
- | BCS {branch_opcode = 0xF1;}
- | BEQ {branch_opcode = 0xF3;}
- | BG {branch_opcode = 0xF8;}
- | BGE {branch_opcode = 0xFA;}
- | BGT {branch_opcode = 0xFC;}
- | BL {branch_opcode = 0xF9;}
- | BLE {branch_opcode = 0xFD;}
- | BLT {branch_opcode = 0xFB;}
- | BMI {branch_opcode = 0xF7;}
- | BNE {branch_opcode = 0xF2;}
- | BNV {branch_opcode = 0xF4;}
- | BOV {branch_opcode = 0xF5;}
- | BPL {branch_opcode = 0xF6;}
- | BR {branch_opcode = 0xFE;}
- | JZ {branch_opcode = 0xEC;}
- | JNZ {branch_opcode = 0xEE;}
-
-
-
-%%
-
-
-int reg(int reg_spec)
-{
- return reg_spec & 15;
-}
-
-int reg_indirect(int reg_spec)
-{
- if (reg_spec & BYTE_REG)
- error("Indirect addressing may not use byte registers");
- if ((reg_spec & 15) > 7)
- error("Only R0 through R7 may be used for indirect addr");
- return reg_spec & 7;
-}
-
-int rel16(int pos, int dest)
-{
- int rel;
-
- if (!p3) return 0; /* don't bother unless writing code */
- if (dest & (BRANCH_SPACING - 1))
- error("Attempt to jump to unaligned location");
- pos &= ~(BRANCH_SPACING - 1);
- rel = (dest - pos) / BRANCH_SPACING;
- if (rel < -32768 || rel > 32767)
- error("Attempt to jump out of 16 bit relative range");
- if (rel < 0) rel += 65536;
- return rel;
-}
-
-int rel8(int pos, int dest)
-{
- int rel;
-
- if (!p3) return 0; /* don't bother unless writing code */
- if (dest & (BRANCH_SPACING - 1))
- error("Attempt to jump to unaligned location");
- pos &= ~(BRANCH_SPACING - 1);
- rel = (dest - pos) / BRANCH_SPACING;
- if (rel < -128 || rel > 127)
- error("Attempt to jump out of 16 bit relative range");
- if (rel < 0) rel += 256;
- return rel;
-}
-
-int msb(int value)
-{
- return (value >> 8) & 255;
-}
-
-int lsb(int value)
-{
- return value & 255;
-}
-
-int direct_addr(int value)
-{
- char buf[250];
-
- if (value < 0 || value > 2047) {
- sprintf(buf, "illegal value (%d) for direct address", value);
- error(buf);
- }
- return value;
-}
-
-int imm_data4_signed(int value)
-{
- if (value < -8 || value > 7)
- error("illegal 4 bit (signed) value");
- if (value >= 0) return value;
- else return (16 + value);
-}
-
-int imm_data4_unsigned(int value)
-{
- if (value < 0 || value > 15)
- error("illegal 4 bit (unsigned) value");
- return value;
-}
-
-int imm_data5_unsigned(int value)
-{
- if (value < 0 || value > 31)
- error("illegal 5 bit (unsigned) value");
- return value;
-}
-
-int imm_data8(int value)
-{
- if (value < -128 || value > 255)
- error("illegal 8 bit value");
- if (value >= 0) return value;
- else return (256 + value);
-}
-
-int imm_data16(int value)
-{
- if (value < -32728 || value > 65535)
- error("illegal 16 bit value");
- if (value >= 0) return value;
- else return (65536 + value);
-}
-
-int bit_addr(int value)
-{
- if (value < 0 || value > 1023) {
- fprintf(stderr, "bad bit addr of 0x%04X (%d dec)\n",
- value, value);
- error("illegal bit address");
- }
- return value;
-}
-
-
-int find_size_reg(int op1spec)
-{
- int op1size=UNKNOWN;
-
- if (op1spec & BYTE_REG) op1size = SIZE8;
- if (op1spec & WORD_REG) op1size = SIZE16;
- if (op1size == UNKNOWN)
- error("Register without implied size");
- return op1size;
-}
-
-int find_size0(int isize)
-{
- if (isize == UNKNOWN)
- error("Can't determine data size from instruction");
- return isize;
-}
-
-int find_size1(int isize, int op1spec)
-{
- int op1size=UNKNOWN;
-
- if (op1spec & BYTE_REG) op1size = SIZE8;
- if (op1spec & WORD_REG) op1size = SIZE16;
- if (op1size == UNKNOWN)
- error("Register without implied size");
-
- if (isize == SIZE32 && op1size == SIZE16) return SIZE32;
- if (isize == UNKNOWN) return op1size;
- else {
- if (isize != op1size)
- error("data size of register and inst don't agree");
- return isize;
- }
-}
-
-int find_size2(int isize, int op1spec, int op2spec)
-{
- int op1size=UNKNOWN, op2size=UNKNOWN;
-
- if (op1spec & BYTE_REG) op1size = SIZE8;
- if (op1spec & WORD_REG) op1size = SIZE16;
- if (op1size == UNKNOWN)
- error("Register without implied size");
- if (op2spec & BYTE_REG) op2size = SIZE8;
- if (op2spec & WORD_REG) op2size = SIZE16;
- if (op1size == UNKNOWN)
- error("Register without implied size");
-
- if (op1size != op2size)
- error("data sizes of two registers don't agree");
- if (isize == UNKNOWN) return op1size;
- else {
- if (isize != op1size)
- error("data size of registers and inst don't agree");
- return isize;
- }
-}
-
-
-int yyerror(char *s)
-{
- if (yytext[0] >= 32) {
- fprintf(stderr, "%s near '%s', line %d\n",
- s, yytext, lineno);
- } else {
- fprintf(stderr, "%s, line %d\n", s, lineno - 1);
- }
- return 0;
-}
-
-void error(char *s)
-{
- yyerror(s);
- exit(1);
-}
-
-int yywrap()
-{
- return 1;
-}
+++ /dev/null
-/* This file is part of Paul's XA51 Assembler, Copyright 1997,2002 Paul Stoffregen
- *
- * Paul's XA51 Assembler is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2.
- *
- * Paul's XA51 Assembler is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* Author contact: paul@pjrc.com */
-
-
-#include <stdio.h>
-
-#define MAXHEXLINE 32 /* the maximum number of bytes to put in one line */
-
-extern FILE *fhex; /* the file to put intel hex into */
-
-
-/* produce intel hex file output */
-
-void hexout(int byte, int memory_location, int end)
-{
- static int byte_buffer[MAXHEXLINE];
- static int last_mem, buffer_pos, buffer_addr;
- static int writing_in_progress=0;
- register int i, sum;
-
- if (!writing_in_progress) {
- /* initial condition setup */
- last_mem = memory_location-1;
- buffer_pos = 0;
- buffer_addr = memory_location;
- writing_in_progress = 1;
- }
-
- if ( (memory_location != (last_mem+1)) || (buffer_pos >= MAXHEXLINE) \
- || ((end) && (buffer_pos > 0)) ) {
- /* it's time to dump the buffer to a line in the file */
- fprintf(fhex, ":%02X%04X00", buffer_pos, buffer_addr);
- sum = buffer_pos + ((buffer_addr>>8)&255) + (buffer_addr&255);
- for (i=0; i < buffer_pos; i++) {
- fprintf(fhex, "%02X", byte_buffer[i]&255);
- sum += byte_buffer[i]&255;
- }
- fprintf(fhex, "%02X\n", (-sum)&255);
- buffer_addr = memory_location;
- buffer_pos = 0;
- }
-
- if (end) {
- fprintf(fhex, ":00000001FF\n"); /* end of file marker */
- fclose(fhex);
- writing_in_progress = 0;
- }
-
- last_mem = memory_location;
- byte_buffer[buffer_pos] = byte & 255;
- buffer_pos++;
-}
-
-
/* adapted from the osu8asm project, 1995 */
/* http://www.pjrc.com/tech/osu8/index.html */
+#define D(x) x
#include <stdio.h>
#include <stdlib.h>
#include "xa_main.h"
extern void yyrestart(FILE *new_file);
-extern void hexout(int byte, int memory_location, int end);
extern int yyparse();
+char modulename[PATH_MAX];
+char infilename[PATH_MAX];
+char outfilename[PATH_MAX];
+char listfilename[PATH_MAX];
+char symfilename[PATH_MAX];
+
/* global variables */
-FILE *fhex, *fmem, *list_fp, *sym_fp;
+FILE *frel, *fmem, *list_fp, *sym_fp;
extern FILE *yyin;
extern char *yytext;
extern char last_line_text[];
struct area_struct area[NUM_AREAS];
int current_area=AREA_CSEG;
+char rel_line[2][132];
char *areaToString (int area) {
switch (area)
{
struct symbol *new, *p;
-/* printf(" Symbol: %s Line: %d\n", thename, lineno); */
+ if ((p=findSymbol(thename))) {
+ p->area=current_area;
+ //fprintf (stderr, "warning, symbol %s already defined\n", thename);
+ return p;
+ }
+
+ //printf(" Symbol: %s Line: %d\n", thename, lineno);
new = (struct symbol *) malloc(sizeof(struct symbol));
new->name = (char *) malloc(strlen(thename)+1);
strcpy(new->name, thename);
new->isreg = 0;
new->line_def = lineno - 1;
new->area = current_area;
+ new->mode = 'X'; // start with an external
new->next = NULL;
if (sym_list == NULL) return (sym_list = new);
p = sym_list;
return (new);
}
-int assign_value(char *thename, int thevalue)
+struct symbol *findSymbol (char *thename) {
+ struct symbol *p;
+ for (p=sym_list; p; p=p->next) {
+ if (strcasecmp(thename, p->name)==0) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+int assign_value(char *thename, int thevalue, char mode)
{
struct symbol *p;
if (!(strcasecmp(thename, p->name))) {
p->value = thevalue;
p->isdef = 1;
+ p->mode = mode;
return (0);
}
p = p->next;
exit(1);
}
-int mk_bit(char *thename)
+int mk_bit(char *thename, int area)
{
struct symbol *p;
while (p != NULL) {
if (!(strcasecmp(thename, p->name))) {
p->isbit = 1;
+ p->area = area;
return (0);
}
p = p->next;
while (p != NULL) {
if (!(strcasecmp(thename, p->name))) {
p->issfr = 1;
+ p->area = 0;
return (0);
}
p = p->next;
void check_redefine()
{
- struct symbol *p1, *p2;
- p1 = sym_list;
- while (p1 != NULL) {
- p2 = p1->next;
- while (p2 != NULL) {
- if (!strcasecmp(p1->name, p2->name)) {
- fprintf(stderr, "Error: symbol '%s' redefined on line %d", p1->name, p2->line_def);
- fprintf(stderr, ", first defined on line %d\n", p1->line_def);
- exit(1);
- }
- p2 = p2->next;
- }
- p1 = p1->next;
- }
+ struct symbol *p1, *p2;
+ p1 = sym_list;
+ while (p1 != NULL) {
+ p2 = p1->next;
+ while (p2 != NULL) {
+ if (!strcasecmp(p1->name, p2->name)) {
+ fprintf(stderr, "Error: symbol '%s' redefined on line %d",
+ p1->name, p2->line_def);
+ fprintf(stderr, ", first defined on line %d\n", p1->line_def);
+ exit(1);
+ }
+ p2 = p2->next;
+ }
+ p1 = p1->next;
+ }
}
int is_target(char *thename)
}
-int is_def(char *thename)
+struct symbol *is_def(char *thename)
{
- struct symbol *p;
- p = sym_list;
- while (p != NULL) {
- if (!strcasecmp(thename, p->name) && p->isdef) return(1);
- p = p->next;
- }
- return (0);
+ struct symbol *p;
+ p = sym_list;
+ while (p != NULL) {
+ if (!strcasecmp(thename, p->name) && p->isdef)
+ return p;
+ p = p->next;
+ }
+ return NULL;
+}
+
+struct symbol *is_ref(char *thename) {
+ struct symbol *p;
+ p = sym_list;
+ while (p != NULL) {
+ if (strcasecmp(thename, p->name)==0)
+ return p;
+ p = p->next;
+ }
+ return NULL;
}
/* this routine is used to dump a group of bytes to the output */
/* though is it expected that the lexer has placed all the actual */
/* original text from the line in "last_line_text" */
-void out(int *byte_list, int num)
-{
- int i, first=1;
-
- if (num > 0) fprintf(list_fp, "%06X: ", MEM_POS);
- else fprintf(list_fp, "\t");
-
- if (current_area==AREA_CSEG || current_area==AREA_XINIT) {
- for (i=0; i<num; i++) {
- hexout(byte_list[i], MEM_POS + i, 0);
- if (!first && (i % 4) == 0) fprintf(list_fp, "\t");
- fprintf(list_fp, "%02X", byte_list[i]);
- if ((i+1) % 4 == 0) {
- if (first) fprintf(list_fp, "\t%s\n", last_line_text);
- else fprintf(list_fp, "\n");
- first = 0;
- } else {
- if (i<num-1) fprintf(list_fp, " ");
- }
+static short last_area=-1;
+
+int debug=0;
+
+void out(int *byte_list, int num) {
+ struct symbol *p;
+ int i, first=1;
+
+ if (num > 0) fprintf(list_fp, "%06X: ", MEM_POS);
+ else fprintf(list_fp, "\t");
+
+ if (last_area!=current_area) {
+ // emit area information
+ fprintf (frel, "A %s size %d flags 0\n",
+ areaToString(current_area),
+ area[current_area].size);
+ area[current_area].defsEmitted=1;
+ if (!area[current_area].defsEmitted) {
+ for (p=sym_list; p; p=p->next) {
+ if (p->isdef && p->area==current_area) {
+ if (debug || p->name[strlen(p->name)-1]!='$') {
+ fprintf (frel, "S %s Def%04x\n", p->name, p->value);
}
}
- if (first) {
- if (num < 3) fprintf(list_fp, "\t");
- fprintf(list_fp, "\t%s\n", last_line_text);
- } else {
- if (num % 4) fprintf(list_fp, "\n");
+ }
+ }
+ last_area=current_area;
+ }
+ if (current_area==AREA_CSEG ||
+ current_area==AREA_GSFINAL ||
+ current_area==AREA_XINIT) {
+ if (num) {
+ fprintf (frel, "T %02x %02x", (MEM_POS>>16)&0xff, MEM_POS&0xff);
+ for (i=0; i<num; i++) {
+ fprintf (frel, " %02x", byte_list[i]);
+ }
+ fprintf (frel, "\n");
+ if (rel_line[0][0]) {
+ fprintf (frel, "%s\n", rel_line[0]);
+ if (rel_line[1][0]) {
+ fprintf (frel, "%s\n", rel_line[1]);
}
+ }
+ }
+ for (i=0; i<num; i++) {
+ if (!first && (i % 4) == 0) fprintf(list_fp, "\t");
+ fprintf(list_fp, "%02X", byte_list[i]);
+ if ((i+1) % 4 == 0) {
+ if (first) fprintf(list_fp, "\t%s\n", last_line_text);
+ else fprintf(list_fp, "\n");
+ first = 0;
+ } else {
+ if (i<num-1) fprintf(list_fp, " ");
+ }
+ }
+ }
+ if (first) {
+ if (num < 3) fprintf(list_fp, "\t");
+ fprintf(list_fp, "\t%s\n", last_line_text);
+ } else {
+ if (num % 4) fprintf(list_fp, "\n");
+ }
+ expr_var[0][0]='\0';
+ expr_var[1][0]='\0';
+ rel_line[0][0]='\0';
+ rel_line[1][0]='\0';
}
}
void addAreaSymbols() {
- char buffer[132];
- int i;
+ //char buffer[132];
+ int i, areas=0, globals=0;
+ struct symbol *p;
+
+ fprintf (frel, "XH\n");
for (i=0; i<NUM_AREAS; i++) {
+ if ((area[i].size=area[i].alloc_position-area[i].start)) {
+ areas++;
+ }
+#if 0
current_area=i;
sprintf (buffer, "s_%s", areaToString(i));
build_sym_list (buffer);
- assign_value (buffer, area[i].start);
buffer[0]='l';
build_sym_list (buffer);
- assign_value (buffer, area[i].alloc_position-area[i].start);
+#endif
+ }
+ for (p=sym_list; p; p=p->next) {
+ if (p->isdef) {
+ if (debug || p->name[strlen(p->name)-1]!='$') {
+ globals++;
+ }
+ }
+ }
+ fprintf (frel, "H %d areas %d global symbols\n", areas, globals);
+ fprintf (frel, "M %s\n", modulename);
+ for (p=sym_list; p; p=p->next) {
+ if (!p->isdef) {
+ fprintf (frel, "S %s Ref0000\n", p->name);
+ }
}
}
printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
}
-char infilename[PATH_MAX];
-char outfilename[PATH_MAX];
-char listfilename[PATH_MAX];
-char symfilename[PATH_MAX];
-//char mapfilename[PATH_MAX];
-
int verbose=0, createSymbolFile=0;
void process_args(int argc, char **argv)
print_usage(1);
}
- strcpy(outfilename, infilename);
- outfilename[strlen(outfilename)-3] = '\0';
- strcpy(listfilename, outfilename);
+ strcpy(modulename, infilename);
+ modulename[strlen(modulename)-3] = '\0';
+ sprintf (outfilename, "%s.rel", modulename);
+ sprintf (listfilename, "%s.lst", modulename);
if (createSymbolFile) {
- strcpy(symfilename, outfilename);
- strcat(symfilename, ".sym");
+ sprintf (symfilename, "%s.sym", modulename);
}
- //strcpy(mapfilename, outfilename);
- strcat(outfilename, ".hex");
- strcat(listfilename, ".lst");
- //strcat(mapfilename, ".map");
}
/* pass #1 (p1=1) find all symbol defs and branch target names */
fprintf(stderr, "Can't open file '%s'.\n", infilename);
exit(1);
}
- fhex = fopen(outfilename, "w");
- if (fhex == NULL) {
+ frel = fopen(outfilename, "w");
+ if (frel == NULL) {
fprintf(stderr, "Can't write file '%s'.\n", outfilename);
exit(1);
}
yyparse();
fclose(yyin);
- hexout(0, 0, 1); /* flush and close intel hex file output */
return 0;
}
int isbit; /* 1 if a bit address, 0 otherwise */
int issfr;
int isreg; /* 1 if a register, 0 otehrwise */
- int area; /* the area that this symbol is in */
+ char mode; /* Absolute, Relative, Tmplabel, eXternal */
+ short lk_index; /* symbol index for the linker */
+ int area; /* the area that this symbol is in */
struct symbol *next; };
/* a list of all the symbols that are branch targets */
struct area_struct {
int start;
int alloc_position;
+ int defsEmitted;
+ int size;
};
extern int current_area;
#define MEM_POS (area[current_area].alloc_position)
enum {
- AREA_CSEG=0,
+ AREA_CSEG=1,
AREA_DSEG,
// AREA_OSEG,
// AREA_ISEG,
AREA_GSFINAL,
AREA_HOME,
AREA_SSEG,
- NUM_AREAS
+ NUM_AREAS=AREA_SSEG
};
extern struct area_struct area[NUM_AREAS];
extern int p1, p2, p3, mem, m_len;
extern struct symbol * build_sym_list(char *thename);
-extern int assign_value(char *thename, int thevalue);
-extern int mk_bit(char *thename);
+extern int assign_value(char *thename, int thevalue, char mode);
+extern int mk_bit(char *thename, int current_area);
extern int mk_reg(char *thename);
extern void out(int *byte_list, int num);
extern int is_target(char *thename);
extern void pad_with_nop();
extern int binary2int(char *str);
-extern int is_def(char *thename);
+extern int is_bit(char *thename);
+extern int is_reg(char *thename);
+extern struct symbol * is_def(char *thename);
+extern struct symbol * is_ref(char *thename);
extern int get_value(char *thename);
-
+extern struct symbol *findSymbol (char *thename);
+extern char rel_line[2][132];
+extern char expr_var[2][MAX_SYMBOL];
+extern void error(char*);
+int mk_bit(char*, int);
+int mk_sfr(char*);
+struct target * build_target_list(char *thename);
+struct symbol * build_sym_list(char *);
+int find_size_reg(int op1spec);
+int find_size0(int isize);
+int find_size1(int isize, int op1spec);
+int find_size2(int isize, int op1spec, int op2spec);
+int yyerror(char *s);
+int imm_data4_signed(int value);
+int imm_data4_unsigned(int value);
+int imm_data5_unsigned(int value);
+int imm_data8(int value);
+int imm_data16(int value);
+int reg(int reg_spec);
+int reg_indirect(int reg_spec);
+int lsb(int value);
+int msb(int value);
+int direct_addr(int value);
+int bit_addr(int value);
+int rel16(int pos, int dest);
+int rel8(int pos, int dest);
+char *areaToString (int area);
+
+FILE *frel, *fmem, *list_fp, *sym_fp;
+
+extern void relout();
--- /dev/null
+%{
+/* This file is part of Paul's XA51 Assembler, Copyright 1997,2002 Paul Stoffregen
+ *
+ * Paul's XA51 Assembler is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * Paul's XA51 Assembler is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Author contact: paul@pjrc.com */
+
+#include <stdio.h>
+#include <string.h>
+#include "xa_main.h"
+#include "xa_rasm.tab.h"
+
+extern int inst_size, yylval;
+char line_text[MAX_LINE]={'\0'}, last_line_text[MAX_LINE];
+char lex_sym_name[MAX_SYMBOL];
+extern char base_symbol_name[];
+#define LIST if (p3) strcat(line_text, yytext)
+%}
+
+%%
+
+add\.w {LIST; inst_size=SIZE16; return ADD;}
+add\.b {LIST; inst_size=SIZE8; return ADD;}
+add {LIST; inst_size=UNKNOWN; return ADD;}
+addc\.w {LIST; inst_size=SIZE16; return ADDC;}
+addc\.b {LIST; inst_size=SIZE8; return ADDC;}
+addc {LIST; inst_size=UNKNOWN; return ADDC;}
+adds\.w {LIST; inst_size=SIZE16; return ADDS;}
+adds\.b {LIST; inst_size=SIZE8; return ADDS;}
+adds {LIST; inst_size=UNKNOWN; return ADDS;}
+and\.w {LIST; inst_size=SIZE16; return AND;}
+and\.b {LIST; inst_size=SIZE8; return AND;}
+and {LIST; inst_size=UNKNOWN; return AND;}
+anl {LIST; inst_size=UNKNOWN; return ANL;}
+asl\.d {LIST; inst_size=SIZE32; return ASL;}
+asl\.w {LIST; inst_size=SIZE16; return ASL;}
+asl\.b {LIST; inst_size=SIZE8; return ASL;}
+asl {LIST; inst_size=UNKNOWN; return ASL;}
+asr\.d {LIST; inst_size=SIZE32; return ASR;}
+asr\.w {LIST; inst_size=SIZE16; return ASR;}
+asr\.b {LIST; inst_size=SIZE8; return ASR;}
+asr {LIST; inst_size=UNKNOWN; return ASR;}
+bcc {LIST; inst_size=UNKNOWN; return BCC;}
+bcs {LIST; inst_size=UNKNOWN; return BCS;}
+beq {LIST; inst_size=UNKNOWN; return BEQ;}
+bg {LIST; inst_size=UNKNOWN; return BG;}
+bge {LIST; inst_size=UNKNOWN; return BGE;}
+bgt {LIST; inst_size=UNKNOWN; return BGT;}
+bkpt {LIST; inst_size=UNKNOWN; return BKPT;}
+bl {LIST; inst_size=UNKNOWN; return BL;}
+ble {LIST; inst_size=UNKNOWN; return BLE;}
+blt {LIST; inst_size=UNKNOWN; return BLT;}
+bmi {LIST; inst_size=UNKNOWN; return BMI;}
+bne {LIST; inst_size=UNKNOWN; return BNE;}
+bnv {LIST; inst_size=UNKNOWN; return BNV;}
+bov {LIST; inst_size=UNKNOWN; return BOV;}
+bpl {LIST; inst_size=UNKNOWN; return BPL;}
+br {LIST; inst_size=UNKNOWN; return BR;}
+call {LIST; inst_size=UNKNOWN; return CALL;}
+cjne\.w {LIST; inst_size=SIZE16; return CJNE;}
+cjne\.b {LIST; inst_size=SIZE8; return CJNE;}
+cjne {LIST; inst_size=UNKNOWN; return CJNE;}
+clr {LIST; inst_size=UNKNOWN; return CLR;}
+cmp\.w {LIST; inst_size=SIZE16; return CMP;}
+cmp\.b {LIST; inst_size=SIZE8; return CMP;}
+cmp {LIST; inst_size=UNKNOWN; return CMP;}
+cpl\.w {LIST; inst_size=SIZE16; return CPL;}
+cpl\.b {LIST; inst_size=SIZE8; return CPL;}
+cpl {LIST; inst_size=UNKNOWN; return CPL;}
+da\.b {LIST; inst_size=SIZE8; return DA;}
+da {LIST; inst_size=UNKNOWN; return DA;}
+div\.d {LIST; inst_size=SIZE32; return DIV;}
+div\.w {LIST; inst_size=SIZE16; return DIV;}
+div\.b {LIST; inst_size=SIZE8; return DIV;}
+div {LIST; inst_size=UNKNOWN; return DIV;}
+divu\.d {LIST; inst_size=SIZE32; return DIVU;}
+divu\.w {LIST; inst_size=SIZE16; return DIVU;}
+divu\.b {LIST; inst_size=SIZE8; return DIVU;}
+divu {LIST; inst_size=UNKNOWN; return DIVU;}
+djnz\.w {LIST; inst_size=SIZE16; return DJNZ;}
+djnz\.b {LIST; inst_size=SIZE8; return DJNZ;}
+djnz {LIST; inst_size=UNKNOWN; return DJNZ;}
+fcall {LIST; inst_size=UNKNOWN; return FCALL;}
+fjmp {LIST; inst_size=UNKNOWN; return FJMP;}
+jb {LIST; inst_size=UNKNOWN; return JB;}
+jbc {LIST; inst_size=UNKNOWN; return JBC;}
+jmp {LIST; inst_size=UNKNOWN; return JMP;}
+jnb {LIST; inst_size=UNKNOWN; return JNB;}
+jnz {LIST; inst_size=UNKNOWN; return JNZ;}
+jz {LIST; inst_size=UNKNOWN; return JZ;}
+lea\.w {LIST; inst_size=SIZE16; return LEA;}
+lea {LIST; inst_size=UNKNOWN; return LEA;}
+lsr\.d {LIST; inst_size=SIZE32; return LSR;}
+lsr\.w {LIST; inst_size=SIZE16; return LSR;}
+lsr\.b {LIST; inst_size=SIZE8; return LSR;}
+lsr {LIST; inst_size=UNKNOWN; return LSR;}
+mov\.w {LIST; inst_size=SIZE16; return MOV;}
+mov\.b {LIST; inst_size=SIZE8; return MOV;}
+mov {LIST; inst_size=UNKNOWN; return MOV;}
+movc\.w {LIST; inst_size=SIZE16; return MOVC;}
+movc\.b {LIST; inst_size=SIZE8; return MOVC;}
+movc {LIST; inst_size=UNKNOWN; return MOVC;}
+movs\.w {LIST; inst_size=SIZE16; return MOVS;}
+movs\.b {LIST; inst_size=SIZE8; return MOVS;}
+movs {LIST; inst_size=UNKNOWN; return MOVS;}
+movx\.w {LIST; inst_size=SIZE16; return MOVX;}
+movx\.b {LIST; inst_size=SIZE8; return MOVX;}
+movx {LIST; inst_size=UNKNOWN; return MOVX;}
+mul\.d {LIST; inst_size=SIZE32; return MUL;}
+mul\.w {LIST; inst_size=SIZE16; return MUL;}
+mul\.b {LIST; inst_size=SIZE8; return MUL;}
+mul {LIST; inst_size=UNKNOWN; return MUL;}
+mulu\.d {LIST; inst_size=SIZE32; return MULU;}
+mulu\.w {LIST; inst_size=SIZE16; return MULU;}
+mulu\.b {LIST; inst_size=SIZE8; return MULU;}
+mulu {LIST; inst_size=UNKNOWN; return MULU;}
+neg\.w {LIST; inst_size=SIZE16; return NEG;}
+neg\.b {LIST; inst_size=SIZE8; return NEG;}
+neg {LIST; inst_size=UNKNOWN; return NEG;}
+nop {LIST; inst_size=UNKNOWN; return NOP;}
+norm\.d {LIST; inst_size=SIZE32; return NORM;}
+norm\.w {LIST; inst_size=SIZE16; return NORM;}
+norm\.b {LIST; inst_size=SIZE8; return NORM;}
+norm {LIST; inst_size=UNKNOWN; return NORM;}
+or\.w {LIST; inst_size=SIZE16; return OR;}
+or\.b {LIST; inst_size=SIZE8; return OR;}
+or {LIST; inst_size=UNKNOWN; return OR;}
+orl {LIST; inst_size=UNKNOWN; return ORL;}
+pop\.w {LIST; inst_size=SIZE16; return POP;}
+pop\.b {LIST; inst_size=SIZE8; return POP;}
+pop {LIST; inst_size=UNKNOWN; return POP;}
+popu\.w {LIST; inst_size=SIZE16; return POPU;}
+popu\.b {LIST; inst_size=SIZE8; return POPU;}
+popu {LIST; inst_size=UNKNOWN; return POPU;}
+push\.w {LIST; inst_size=SIZE16; return PUSH;}
+push\.b {LIST; inst_size=SIZE8; return PUSH;}
+push {LIST; inst_size=UNKNOWN; return PUSH;}
+pushu\.w {LIST; inst_size=SIZE16; return PUSHU;}
+pushu\.b {LIST; inst_size=SIZE8; return PUSHU;}
+pushu {LIST; inst_size=UNKNOWN; return PUSHU;}
+reset {LIST; inst_size=UNKNOWN; return RESET;}
+ret {LIST; inst_size=UNKNOWN; return RET;}
+reti {LIST; inst_size=UNKNOWN; return RETI;}
+rl\.w {LIST; inst_size=SIZE16; return RL;}
+rl\.b {LIST; inst_size=SIZE8; return RL;}
+rl {LIST; inst_size=UNKNOWN; return RL;}
+rlc\.w {LIST; inst_size=SIZE16; return RLC;}
+rlc\.b {LIST; inst_size=SIZE8; return RLC;}
+rlc {LIST; inst_size=UNKNOWN; return RLC;}
+rr\.w {LIST; inst_size=SIZE16; return RR;}
+rr\.b {LIST; inst_size=SIZE8; return RR;}
+rr {LIST; inst_size=UNKNOWN; return RR;}
+rrc\.w {LIST; inst_size=SIZE16; return RRC;}
+rrc\.b {LIST; inst_size=SIZE8; return RRC;}
+rrc {LIST; inst_size=UNKNOWN; return RRC;}
+setb {LIST; inst_size=UNKNOWN; return SETB;}
+sext\.w {LIST; inst_size=SIZE16; return SEXT;}
+sext\.b {LIST; inst_size=SIZE8; return SEXT;}
+sext {LIST; inst_size=UNKNOWN; return SEXT;}
+sub\.w {LIST; inst_size=SIZE16; return SUB;}
+sub\.b {LIST; inst_size=SIZE8; return SUB;}
+sub {LIST; inst_size=UNKNOWN; return SUB;}
+subb\.w {LIST; inst_size=SIZE16; return SUBB;}
+subb\.b {LIST; inst_size=SIZE8; return SUBB;}
+subb {LIST; inst_size=UNKNOWN; return SUBB;}
+trap {LIST; inst_size=UNKNOWN; return TRAP;}
+xch\.w {LIST; inst_size=SIZE16; return XCH;}
+xch\.b {LIST; inst_size=SIZE8; return XCH;}
+xch {LIST; inst_size=UNKNOWN; return XCH;}
+xor\.w {LIST; inst_size=SIZE16; return XOR;}
+xor\.b {LIST; inst_size=SIZE8; return XOR;}
+xor {LIST; inst_size=UNKNOWN; return XOR;}
+
+
+dptr {LIST; return DPTR;}
+pc {LIST; return PC;}
+a {LIST; return A;}
+c {LIST; return C;}
+usp {LIST; return USP;}
+
+org {LIST; return ORG;}
+equ {LIST; return EQU;}
+sfr {LIST; return SFR;}
+db {LIST; return DB;}
+dw {LIST; return DW;}
+byte {LIST; return DB;}
+bit {LIST; return BITDEF;}
+reg {LIST; return REGDEF;}
+area {LIST; return AREA;}
+ds {LIST; return DS;}
+DSEG {LIST; yylval = AREA_DSEG; return AREA_NAME;}
+BSEG {LIST; yylval = AREA_BSEG; return AREA_NAME;}
+XSEG {LIST; yylval = AREA_XSEG; return AREA_NAME;}
+XISEG {LIST; yylval = AREA_XISEG; return AREA_NAME;}
+XINIT {LIST; yylval = AREA_XINIT; return AREA_NAME;}
+GSINIT {LIST; yylval = AREA_GSINIT; return AREA_NAME;}
+GSFINAL {LIST; yylval = AREA_GSFINAL; return AREA_NAME;}
+HOME {LIST; yylval = AREA_HOME; return AREA_NAME;}
+SSEG {LIST; yylval = AREA_SSEG; return AREA_NAME;}
+CSEG {LIST; yylval = AREA_CSEG; return AREA_NAME;}
+module {LIST; return MODULE;}
+globl {LIST; return GLOBL;}
+\(DATA\) {LIST; return AREA_DESC;}
+\(OVR,XDATA\) {LIST; return AREA_DESC;}
+\(BIT\) {LIST; return AREA_DESC;}
+\(XDATA\) {LIST; return AREA_DESC;}
+\(CODE\) {LIST; return AREA_DESC;}
+low {LIST; return LOW;}
+high {LIST; return HIGH;}
+>> {LIST; return RSHIFT;}
+\<\< {LIST; return LSHIFT;}
+
+R[0-9] {LIST; yylval = yytext[1] - '0' + WORD_REG; return REG;}
+R1[0-5] {LIST; yylval = yytext[2] - '0' + 10 + WORD_REG; return REG;}
+R[0-7]L {LIST; yylval = (yytext[1] - '0') * 2 + BYTE_REG; return REG;}
+R[0-7]H {LIST; yylval = (yytext[1] - '0') * 2 + 1 + BYTE_REG; return REG;}
+
+
+[a-z_][a-z0-9_]* {
+ LIST;
+ if (is_def(yytext)) {
+ yylval = get_value(yytext);
+ } else {
+ if (p1) build_sym_list(yytext);
+ yylval = 0;
+ //if (p3) error("Symbol undefined");
+ }
+ /* keep name in lex_sym_name since yytext */
+ /* could be overwritten if the parser does */
+ /* a lookahead operation */
+ strcpy(lex_sym_name, yytext);
+ if (is_def(lex_sym_name)) {
+ yylval = get_value(lex_sym_name);
+ /* return correct type if special */
+ if (is_bit(lex_sym_name)) return BIT;
+ if (is_reg(lex_sym_name)) return REG;
+ }
+ return WORD;
+ }
+[0-9]+\$ {
+ LIST;
+ /* should print error if base_symbol_name */
+ /* is not defined */
+ sprintf(lex_sym_name, "%s:%s",
+ base_symbol_name, yytext);
+ if (is_def(lex_sym_name)) {
+ yylval = get_value(lex_sym_name);
+ } else {
+ yylval = 0;
+ if (p3) error("Symbol undefined");
+ }
+ return WORD;
+ }
+[01]+[bq] {
+ LIST;
+ yylval = binary2int(yytext);
+ return NUMBER;
+ }
+0x[0-9a-f]+ {
+ LIST;
+ sscanf(yytext, "%*c%*c%x", &yylval);
+ return NUMBER;
+ }
+[0-9a-f]+[h] {
+ LIST;
+ sscanf(yytext, "%x%*[hH]", &yylval);
+ return NUMBER;
+ }
+\$[0-9a-f]+ {
+ LIST;
+ sscanf(yytext, "$%x", &yylval);
+ return NUMBER;
+ }
+-?[0-9]+ {
+ LIST;
+ sscanf(yytext, "%d", &yylval);
+ return NUMBER;
+ }
+\'.\' {
+ LIST;
+ yylval = (int)yytext[1];
+ return CHAR;
+ }
+\'\\.\' {
+ LIST;
+ switch (yytext[1]) {
+ case 'n':
+ case 'N': yylval = 10; break;
+ case 'r':
+ case 'R': yylval = 13; break;
+ case '0': yylval = 0; break;
+ default: yylval = (int)yytext[1];
+ /* print a warning here */
+ }
+ return CHAR;
+ }
+\"[^"\n]*["\n] {
+ LIST;
+ return STRING;
+ }
+
+;[^\n]* {LIST; /* comments */}
+[ \t\r] {LIST; /* whitespace */}
+
+\n {
+ strcpy(last_line_text, line_text);
+ line_text[0] = '\0';
+ ++lineno;
+ return EOL;
+ }
+
+. {LIST; return yytext[0];}
+
+%%
--- /dev/null
+%{
+/* This file is part of Paul's XA51 Assembler, Copyright 1997,2002 Paul Stoffregen
+ *
+ * Paul's XA51 Assembler is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * Paul's XA51 Assembler is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Author contact: paul@pjrc.com */
+
+/* parser for the 51-XA assembler, Paul Stoffregen, July 1997 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xa_main.h"
+
+int op[MAX_DB];
+int size;
+int inst_size;
+int arith_opcode, short_opcode, num_op, opcode0, opcode1;
+int shift_imm_opcode, shift_reg_opcode, rotate_opcode;
+int stack_addr_opcode, stack_reg_opcode, branch_opcode;
+int rlist_reg_bank, rlist_bitmask, rlist_size;
+int db_count, dw_count, i;
+char symbol_name[MAX_SYMBOL], base_symbol_name[MAX_SYMBOL]={'\0'};
+char expr_var[2][MAX_SYMBOL]={{'\0'},{'\0'}};
+
+extern char lex_sym_name[];
+extern int yylex();
+
+extern void yyrestart(FILE *new_file);
+extern char * disasm(int byte, int memory_location);
+void error(char *s);
+
+
+void RELOC_FF(unsigned pc, unsigned short offset, short rl) {
+ struct symbol *sym;
+ if ((sym=findSymbol(yytext))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[rl], "R %d REL_FF 0x%04x %s", offset, pc,
+ sym->name);
+ }
+ }
+}
+
+void RELOC_FFFF(unsigned pc, unsigned short offset, short rl) {
+ struct symbol *sym;
+ if ((sym=findSymbol(yytext))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[rl], "R %d REL_FFFF 0x%04x %s", offset, pc,
+ sym->name);
+ }
+ }
+}
+
+void RELOC_ABS_0F(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_0F %s", offset, sym->name);
+ }
+ }
+}
+
+void RELOC_ABS_FF(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_FF %s", offset, sym->name);
+ }
+ }
+}
+
+void RELOC_ABS_03FF(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if (expr_var[0]) {
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_03FF %s", offset, sym->name);
+ }
+ }
+ }
+}
+
+void RELOC_ABS_07ff(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if (expr_var[0]) {
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_07ff %s", offset, sym->name);
+ }
+ }
+ }
+}
+
+void RELOC_ABS_F0FF(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if (expr_var[0]) {
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_F0FF %s", offset, sym->name);
+ }
+ }
+ }
+}
+
+void RELOC_ABS_FFFF(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if (expr_var[0]) {
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+#if 1
+ sprintf (rel_line[expr], "R %d ABS_FFFF %s", offset, sym->name);
+#else
+ sprintf (rel_line[expr], "R 0 0 00 %02x 02 %02x %02x", current_area,
+ (sym->lk_index>>8)&0xff, sym->lk_index&&0xff);
+#endif
+ }
+ }
+ }
+}
+
+void RELOC_ABS_0F00FF(unsigned short offset, int expr) {
+ struct symbol *sym;
+ if (expr_var[0]) {
+ if ((sym=findSymbol(expr_var[expr]))) {
+ if (sym->mode=='X') {
+ sprintf (rel_line[expr], "R %d ABS_0F00FF %s", offset, sym->name);
+ }
+ }
+ }
+}
+
+%}
+
+%token ADD ADDC ADDS AND ANL ASL ASR BCC BCS BEQ BG BGE BGT
+%token BKPT BL BLE BLT BMI BNE BNV BOV BPL BR CALL CJNE CLR
+%token CMP CPL DA DIV DIVU DJNZ FCALL FJMP JB JBC JMP JNB JNZ
+%token JZ LEA LSR MOV MOVC MOVS MOVX MUL MULU NEG NOP NORM
+%token OR ORL POP POPU PUSH PUSHU RESET RET RETI RL RLC RR RRC
+%token SETB SEXT SUB SUBB TRAP XCH XOR
+%token REG DPTR PC A C USP
+%token WORD BIT NUMBER CHAR STRING EOL LOCAL_LABEL
+%token ORG EQU SFR DB DW BITDEF REGDEF LOW HIGH
+%token RSHIFT LSHIFT
+%token AREA AREA_NAME AREA_DESC DS
+%token MODULE GLOBL
+
+%left '&' '|' '^'
+%left RSHIFT LSHIFT
+%left '+' '-'
+%left '*' '/'
+%nonassoc UNARY
+
+%%
+
+all: line
+ | line all;
+
+line: linesymbol ':' linenosym {
+ if (p1) {
+ build_sym_list(symbol_name);
+ if (current_area == AREA_BSEG) {
+ mk_bit(symbol_name, current_area);
+ }
+ }
+ if (p1 || p2) assign_value(symbol_name, MEM_POS, 'R');
+ MEM_POS += $3;
+ }
+ | linenosym {
+ MEM_POS += $1;
+ }
+
+linenosym: directive EOL {
+ if (p3) out(op, $1);
+ $$ = $1;
+ }
+ | instruction EOL {
+ if (p3) out(op, $1);
+ $$ = $1;
+ }
+ | EOL {
+ if (p3) out(NULL, 0);
+ $$ = 0;
+ }
+ | error EOL /* try to recover from any parse error */
+
+
+directive: '.' ORG expr {
+ MEM_POS = $3;
+ $$ = 0;
+ }
+ | ORG expr {
+ MEM_POS = $2;
+ $$ = 0;
+ }
+ | '.' EQU symbol ',' expr {
+ if (p1) build_sym_list(symbol_name);
+ if (p1 || p2) assign_value(symbol_name, $5, '?');
+ $$ = 0;
+ }
+ | normal_or_bit_symbol '=' expr {
+ if (p1) build_sym_list(symbol_name);
+ if (p1 || p2) assign_value(symbol_name, $3, '?');
+ }
+ | symbol SFR expr {
+ if (p1) build_sym_list(symbol_name);
+ if (p1 || p2) assign_value(symbol_name, $3, 'A');
+ if (p1 || p2) mk_sfr(symbol_name);
+ $$ = 0;
+ }
+ | '.' BITDEF bitsymbol ',' bit {
+ if (p1) {
+ build_sym_list(symbol_name);
+ mk_bit(symbol_name, 0);
+ }
+ if (p1 || p2) assign_value(symbol_name, $5, '?');
+ $$ = 0;
+ }
+ | bitsymbol BITDEF bit {
+ if (p1) {
+ build_sym_list(symbol_name);
+ mk_bit(symbol_name, 0);
+ }
+ if (p1 || p2) assign_value(symbol_name, $3, '?');
+ $$ = 0;
+ }
+ | bitsymbol BITDEF expr {
+ if (p1) {
+ build_sym_list(symbol_name);
+ mk_bit(symbol_name, 0);
+ }
+ if (p1 || p2) assign_value(symbol_name, $3, 'A');
+ $$ = 0;
+ }
+ | '.' REGDEF regsymbol ',' REG {
+ if (p1) {
+ build_sym_list(symbol_name);
+ mk_reg(symbol_name);
+ }
+ if (p1 || p2) assign_value(symbol_name, $5, '?');
+ $$ = 0;
+ }
+ | regsymbol REGDEF REG {
+ if (p1) {
+ build_sym_list(symbol_name);
+ mk_reg(symbol_name);
+ }
+ if (p1 || p2) assign_value(symbol_name, $3, '?');
+ $$ = 0;
+ }
+
+ | '.' db_directive bytes {
+ $$ = db_count;
+ }
+ | '.' dw_directive words {
+ $$ = dw_count;
+ }
+ | '.' AREA AREA_NAME AREA_DESC {
+ if ($3 < 0 || $3 > NUM_AREAS) {
+ error("Illegal Area Directive");
+ }
+ symbol_name[0] = '\0';
+ current_area = $3;
+ $$ = 0;
+ }
+ | '.' MODULE WORD {
+ /* ignore module definition */
+ $$ = 0;
+ }
+ | '.' GLOBL WORD {
+ /* ignore global symbol declaration */
+ $$ = 0;
+ }
+ | '.' GLOBL bit {
+ /* ignore bit symbol declaration */
+ $$ = 0;
+ }
+ | '.' DS expr {
+ /* todo: if CSEG, emit some filler bytes */
+ $$ = $3;
+ }
+
+db_directive: DB {db_count = 0;}
+
+
+linesymbol: normal_or_bit_symbol {
+ strcpy(symbol_name, lex_sym_name);
+ if (!strchr(lex_sym_name, ':')) {
+ /* non-local label, remember base name */
+ strcpy(base_symbol_name, lex_sym_name);
+ }
+ if (is_target(symbol_name)) pad_with_nop();
+ }
+
+normal_or_bit_symbol: WORD {$$ = $1;}
+ | BIT {$$ = $1;}
+
+bytes: byte_element
+ | bytes ',' byte_element
+
+byte_element: expr {
+ op[db_count] = $1 & 255;
+ if (++db_count >= MAX_DB) {
+ error("too many bytes, use two DB");
+ db_count--;
+ }
+ }
+ | STRING {
+ for(i=1; i < strlen(yytext)-1; i++) {
+ op[db_count++] = yytext[i];
+ if (db_count >= MAX_DB) {
+ error("too many bytes, use two DB");
+ db_count--;
+ }
+ }
+ }
+
+dw_directive: DW {dw_count = 0;}
+
+words: words ',' word_element
+ | word_element
+
+word_element: expr {
+ op[dw_count] = $1 & 255;
+ op[dw_count+1] = ($1 >> 8) & 255;
+ dw_count += 2;
+ if (dw_count >= MAX_DB) {
+ error("too many bytes, use two DW");
+ db_count -= 2;
+ }
+ }
+
+
+
+symbol: WORD {
+ strcpy(symbol_name, lex_sym_name);
+ }
+
+bitsymbol: WORD { strcpy(symbol_name, lex_sym_name); }
+ | BIT { strcpy(symbol_name, lex_sym_name); }
+
+
+regsymbol: WORD { strcpy(symbol_name, lex_sym_name); }
+ | REG { strcpy(symbol_name, lex_sym_name); }
+
+bit: expr '.' expr {
+ if ($3 < 0 || $3 > 7) {
+ /* only 8 bits in a byte */
+ error("Only eight bits in a byte");
+ }
+ $$ = 100000; /* should really check $1 is valid */
+ if ($1 >= 0x20 && $1 <= 0x3F) {
+ $$ = $1 * 8 + $3;
+ }
+ if ($1 >= 0x400 && $1 <= 0x43F) {
+ $$ = ($1 - 0x400) * 8 + $3 + 0x200;
+ }
+ }
+ | REG '.' expr {
+ $$ = 100000;
+ if (find_size_reg($1) == SIZE8) {
+ if ($3 < 0 || $3 > 7)
+ error("byte reg has only 8 bits");
+ $$ = reg($1) * 8 + $3;
+ }
+ if (find_size_reg($1) == SIZE16) {
+ if ($3 < 0 || $3 > 15)
+ error("word reg has only 16 bits");
+ $$ = reg($1) * 16 + $3;
+ }
+ }
+ | BIT {$$ = $1;}
+
+jmpaddr: WORD {
+ $$ = $1;
+ if (p1) build_target_list(lex_sym_name);
+ }
+ | NUMBER {
+ if ($1 & 1) error("Jump target must be aligned");
+ $$ = $1;
+ }
+
+
+expr: value {$$ = $1;}
+ | expr '+' expr {$$ = $1 + $3;}
+ | expr '-' expr {$$ = $1 - $3;}
+ | expr '*' expr {$$ = $1 * $3;}
+ | expr '/' expr {$$ = $1 / $3;}
+ | expr '&' expr {$$ = $1 & $3;}
+ | expr '|' expr {$$ = $1 | $3;}
+ | expr '^' expr {$$ = $1 ^ $3;}
+ | expr RSHIFT expr {$$ = $1 >> $3;}
+ | expr LSHIFT expr {$$ = $1 << $3;}
+ | '-' expr %prec UNARY {$$ = $2 * -1;}
+ | '+' expr %prec UNARY {$$ = $2;}
+ | '(' expr ')' {$$ = $2;}
+ | LOW expr %prec UNARY {$$ = $2 & 255;}
+ | HIGH expr %prec UNARY {$$ = ($2 >> 8) & 255;}
+
+
+value: NUMBER {$$ = $1;}
+ | CHAR {$$ = $1;}
+ | WORD {
+ $$ = $1;
+ if (expr_var[0][0]=='\0') {
+ strcpy(expr_var[0], yytext);
+ } else {
+ strcpy(expr_var[1], yytext);
+ }
+ }
+
+
+rlist: REG {
+ rlist_bitmask = 1<<(reg($1) % 8);
+ rlist_reg_bank = (reg($1) / 8) ? 1 : 0;
+ rlist_size = find_size_reg($1);
+ }
+ | REG ',' rlist {
+ rlist_bitmask |= 1<<(reg($1) % 8);
+ if (rlist_reg_bank != ((reg($1) / 8) ? 1 : 0))
+ error("register list may not mix 0-7/8-15 regs");
+ if (rlist_size != find_size_reg($1))
+ error("register list may not mix 8/16 bit registers");
+ }
+
+
+
+
+
+instruction:
+
+ arith_inst REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ op[0] = arith_opcode * 16 + size * 8 + 1;
+ op[1] = reg($2) * 16 + reg($4);
+ }
+| arith_inst REG ',' '[' REG ']' {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = arith_opcode * 16 + size * 8 + 2;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ }
+| arith_inst '[' REG ']' ',' REG {
+ $$ = 2;
+ size = find_size1(inst_size, $6);
+ op[0] = arith_opcode * 16 + size * 8 + 2;
+ op[1] = reg($6) * 16 + 8 + reg_indirect($3);
+ }
+| arith_inst REG ',' '[' REG '+' expr ']' {
+ size = find_size1(inst_size, $2);
+ if ($7 >= -128 && $7 <= 127) {
+ $$ = 3;
+ op[0] = arith_opcode * 16 + size * 8 + 4;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ op[2] = ($7 >= 0) ? $7 : 256 + $7;
+ RELOC_ABS_FF(2,0);
+ } else {
+ $$ = 4;
+ op[0] = arith_opcode * 16 + size * 8 + 5;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ op[2] = ($7 >= 0) ? msb($7) : msb(65536 + $7);
+ op[3] = ($7 >= 0) ? lsb($7) : lsb(65536 + $7);
+ RELOC_ABS_FFFF(2,0);
+ }
+ }
+| arith_inst '[' REG '+' expr ']' ',' REG {
+ size = find_size1(inst_size, $8);
+ if ($5 >= -128 && $5 <= 127) {
+ $$ = 3;
+ op[0] = arith_opcode * 16 + size * 8 + 4;
+ op[1] = reg($8) * 16 + 8 + reg_indirect($3);
+ op[2] = ($5 >= 0) ? $5 : 256 + $5;
+ RELOC_ABS_FF(2,0);
+ } else {
+ $$ = 4;
+ op[0] = arith_opcode * 16 + size * 8 + 5;
+ op[1] = reg($8) * 16 + 8 + reg_indirect($3);
+ op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
+ op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
+ RELOC_ABS_FFFF(2,0);
+ }
+ }
+| arith_inst REG ',' '[' REG '+' ']' {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = arith_opcode * 16 + size * 8 + 3;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ }
+| arith_inst '[' REG '+' ']' ',' REG {
+ $$ = 2;
+ size = find_size1(inst_size, $7);
+ op[0] = arith_opcode * 16 + size * 8 + 3;
+ op[1] = reg($7) * 16 + 8 + reg_indirect($3);
+ }
+| arith_inst WORD ',' REG {
+ $$ = 3;
+ size = find_size1(inst_size, $4);
+ op[0] = arith_opcode * 16 + size * 8 + 6;
+ op[1] = reg($4) * 16 + 8 + msb(direct_addr($2));
+ op[2] = lsb(direct_addr($2));
+ RELOC_ABS_07ff(1, 0);
+ }
+| arith_inst REG ',' WORD {
+ $$ = 3;
+ size = find_size1(inst_size, $2);
+ op[0] = arith_opcode * 16 + size * 8 + 6;
+ op[1] = reg($2) * 16 + msb(direct_addr($4));
+ op[2] = lsb(direct_addr($4));
+ RELOC_ABS_07ff(1, 0);
+ }
+| arith_inst REG ',' '#' expr {
+ size = find_size1(inst_size, $2);
+ if (size == SIZE8) {
+ $$ = 3;
+ op[0] = 0x91;
+ op[1] = reg($2) * 16 + arith_opcode;
+ op[2] = imm_data8($5);
+ RELOC_ABS_FF(2, 0);
+ } else {
+ $$ = 4;
+ op[0] = 0x99;
+ op[1] = reg($2) * 16 + arith_opcode;
+ op[2] = msb(imm_data16($5));
+ op[3] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF (2, 0);
+ }
+ }
+| arith_inst '[' REG ']' ',' '#' expr {
+ size = find_size0(inst_size);
+ if (size == SIZE8) {
+ $$ = 3;
+ op[0] = 0x92;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = imm_data8($7);
+ RELOC_ABS_FF(2, 0);
+ } else {
+ $$ = 4;
+ op[0] = 0x9A;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = msb(imm_data16($7));
+ op[3] = lsb(imm_data16($7));
+ RELOC_ABS_FFFF (2, 0);
+ }
+ }
+| arith_inst '[' REG '+' ']' ',' '#' expr {
+ size = find_size0(inst_size);
+ if (size == SIZE8) {
+ $$ = 3;
+ op[0] = 0x93;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = imm_data8($8);
+ RELOC_ABS_FF(2, 0);
+ } else {
+ $$ = 4;
+ op[0] = 0x9B;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = msb(imm_data16($8));
+ op[3] = lsb(imm_data16($8));
+ RELOC_ABS_FFFF (2, 0);
+ }
+ }
+| arith_inst '[' REG '+' expr ']' ',' '#' expr {
+ size = find_size0(inst_size);
+ if ($5 >= -128 && $5 <= 127) {
+ if (size == SIZE8) {
+ $$ = 4;
+ op[0] = 0x94;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = ($5 >= 0) ? $5 : 256 + $5;
+ op[3] = imm_data8($9);
+ RELOC_ABS_FF(2, 0);
+ RELOC_ABS_FF(3, 1);
+ } else {
+ $$ = 5;
+ op[0] = 0x9C;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = ($5 >= 0) ? $5 : 256 + $5;
+ op[3] = msb(imm_data16($9));
+ op[4] = lsb(imm_data16($9));
+ RELOC_ABS_FF(2, 0);
+ RELOC_ABS_FFFF(3, 1);
+ }
+ } else {
+ if (size == SIZE8) {
+ $$ = 5;
+ op[0] = 0x95;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
+ op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
+ op[4] = imm_data8($9);
+ RELOC_ABS_FFFF(2,0);
+ RELOC_ABS_FF(4,1);
+ } else {
+ $$ = 6;
+ op[0] = 0x9D;
+ op[1] = reg_indirect($3) * 16 + arith_opcode;
+ op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
+ op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
+ op[4] = msb(imm_data16($9));
+ op[5] = lsb(imm_data16($9));
+ RELOC_ABS_FFFF(2, 0);
+ RELOC_ABS_FFFF(4, 1);
+ }
+ }
+ }
+| arith_inst WORD ',' '#' expr {
+ size = find_size0(inst_size);
+ if (size == SIZE8) {
+ $$ = 4;
+ op[0] = 0x96;
+ op[1] = msb(direct_addr($2)) * 16 + arith_opcode;
+ op[2] = lsb(direct_addr($2));
+ op[3] = imm_data8($5);
+ RELOC_ABS_F0FF(1,0);
+ RELOC_ABS_FF(3,1);
+ } else {
+ $$ = 5;
+ op[0] = 0x9E;
+ op[1] = msb(direct_addr($2)) * 16 + arith_opcode;
+ op[2] = lsb(direct_addr($2));
+ op[3] = msb(imm_data16($5));
+ op[4] = lsb(imm_data16($5));
+ RELOC_ABS_F0FF(1,0);
+ RELOC_ABS_FFFF (3,1);
+ }
+ }
+
+/* the next 8 instructions are MOV, but because MOV was used in the */
+/* arith_inst group, it will cause a shift/reduce conflict if used */
+/* directly below... so we're forced to use arith_inst and then */
+/* add a bit of code to make sure it was MOV and not the other ones */
+
+| arith_inst '[' REG '+' ']' ',' '[' REG '+' ']' {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (1)");
+ size = find_size0(inst_size);
+ $$ = 2;
+ op[0] = 0x90 + size * 8;
+ op[1] = reg_indirect($3) * 16 + reg_indirect($8);
+ }
+| arith_inst WORD ',' '[' REG ']' {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (2)");
+ size = find_size0(inst_size);
+ $$ = 3;
+ op[0] = 0xA0 + size * 8;
+ op[1] = 128 + reg_indirect($5) * 16 + msb(direct_addr($2));
+ op[2] = lsb(direct_addr($2));
+ RELOC_ABS_07ff(1, 0);
+ }
+| arith_inst '[' REG ']' ',' WORD {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (3)");
+ size = find_size0(inst_size);
+ $$ = 3;
+ op[0] = 0xA0 + size * 8;
+ op[1] = reg_indirect($3) * 16 + msb(direct_addr($6));
+ op[2] = lsb(direct_addr($6));
+ RELOC_ABS_07ff(1, 0);
+ }
+| arith_inst WORD ',' WORD {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (4)");
+ size = find_size0(inst_size);
+ $$ = 4;
+ op[0] = 0x97 + size * 8;
+ op[1] = msb(direct_addr($2)) * 16 + msb(direct_addr($4));
+ op[2] = lsb(direct_addr($2));
+ op[3] = lsb(direct_addr($4));
+ RELOC_ABS_F0FF(1, 0);
+ RELOC_ABS_0F00FF(1, 1);
+ }
+| arith_inst REG ',' USP {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (5)");
+ $$ = 2;
+ op[0] = 0x90;
+ op[1] = reg($2) * 16 + 15;
+ }
+| arith_inst USP ',' REG {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (6)");
+ $$ = 2;
+ op[0] = 0x98;
+ op[1] = reg($4) * 16 + 15;
+ }
+| arith_inst C ',' bit {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (7)");
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x20 + msb(bit_addr($4));
+ op[2] = lsb(bit_addr($4));
+ RELOC_ABS_03FF(1, 0);
+ }
+| arith_inst bit ',' C {
+ /* this addr mode is only valid for MOV */
+ if (arith_opcode != 8) error("Addr mode only valid for MOV (8)");
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x30 + msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ RELOC_ABS_03FF(1, 0);
+ }
+
+| MOVC REG ',' '[' REG '+' ']' {
+ size = find_size1(inst_size, $2);
+ $$ = 2;
+ op[0] = 0x80 + size * 8;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ }
+| MOVC A ',' '[' A '+' DPTR ']' {
+ $$ = 2;
+ op[0] = 0x90;
+ op[1] = 0x4E;
+ }
+| MOVC A ',' '[' A '+' PC ']' {
+ $$ = 2;
+ op[0] = 0x90;
+ op[1] = 0x4C;
+ }
+| MOVX REG ',' '[' REG ']' {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0xA7 + size * 8;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ }
+| MOVX '[' REG ']' ',' REG {
+ $$ = 2;
+ size = find_size1(inst_size, $6);
+ op[0] = 0xA7 + size * 8;
+ op[1] = reg($6) * 16 + 8 + reg_indirect($3);
+ }
+| XCH REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ op[0] = 0x60 + size * 8;
+ op[1] = reg($2) * 16 + reg($4);
+ }
+| XCH REG ',' '[' REG ']' {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0x50 + size * 8;
+ op[1] = reg($2) * 16 + reg_indirect($5);
+ }
+| XCH REG ',' WORD {
+ $$ = 3;
+ size = find_size1(inst_size, $2);
+ op[0] = 0xA0 + size * 8;
+ op[1] = reg($2) * 16 + msb(direct_addr($4));
+ op[2] = lsb(direct_addr($4));
+ RELOC_ABS_07ff(1, 0);
+ }
+| short_data_inst REG ',' '#' expr {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = short_opcode + size * 8 + 1;
+ op[1] = reg($2) * 16 + imm_data4_signed($5);
+ RELOC_ABS_0F(1, 0);
+ }
+| short_data_inst '[' REG ']' ',' '#' expr {
+ $$ = 2;
+ size = find_size0(inst_size);
+ op[0] = short_opcode + size * 8 + 2;
+ op[1] = reg_indirect($3) * 16 + imm_data4_signed($7);
+ RELOC_ABS_0F(1, 0);
+ }
+| short_data_inst '[' REG '+' ']' ',' '#' expr {
+ $$ = 2;
+ size = find_size0(inst_size);
+ op[0] = short_opcode + size * 8 + 3;
+ op[1] = reg_indirect($3) * 16 + imm_data4_signed($8);
+ RELOC_ABS_0F(1, 0);
+ }
+| short_data_inst '[' REG '+' expr ']' ',' '#' expr {
+ size = find_size0(inst_size);
+ if ($5 >= -128 && $5 <= 127) {
+ $$ = 3;
+ op[0] = short_opcode + size * 8 + 4;
+ op[1] = reg_indirect($3) * 16 + imm_data4_signed($9);
+ op[2] = op[2] = ($5 >= 0) ? $5 : 256 + $5;
+ RELOC_ABS_0F(1, 1);
+ RELOC_ABS_FF(2, 0);
+ } else {
+ $$ = 4;
+ op[0] = short_opcode + size * 8 + 5;
+ op[1] = reg_indirect($3) * 16 + imm_data4_signed($9);
+ op[2] = ($5 >= 0) ? msb($5) : msb(65536 + $5);
+ op[3] = ($5 >= 0) ? lsb($5) : lsb(65536 + $5);
+ RELOC_ABS_0F(1, 1);
+ RELOC_ABS_FFFF(2, 0);
+ }
+ }
+| short_data_inst expr ',' '#' expr {
+ $$ = 3;
+ size = find_size0(inst_size);
+ op[0] = short_opcode + size * 8 + 6;
+ op[1] = msb(direct_addr($2)) * 16 + imm_data4_signed($5);
+ op[2] = lsb(direct_addr($2));
+ RELOC_ABS_0F(1, 0);
+ }
+| ANL C ',' bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x40 + msb(bit_addr($4));
+ op[2] = lsb(bit_addr($4));
+ RELOC_ABS_03FF(1, 0);
+ }
+| ANL C ',' '/' bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x50 + msb(bit_addr($5));
+ op[2] = lsb(bit_addr($5));
+ RELOC_ABS_03FF(1, 0);
+ }
+
+| ORL C ',' bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x60 + msb(bit_addr($4));
+ op[2] = lsb(bit_addr($4));
+ RELOC_ABS_03FF(1, 0);
+ }
+| ORL C ',' '/' bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x70 + msb(bit_addr($5));
+ op[2] = lsb(bit_addr($5));
+ RELOC_ABS_03FF(1, 0);
+ }
+| CLR bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ RELOC_ABS_03FF(1, 0);
+ }
+| SETB bit {
+ $$ = 3;
+ op[0] = 0x08;
+ op[1] = 0x10 + msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ RELOC_ABS_03FF(1, 0);
+ }
+| logical_shift_inst REG ',' REG {
+ size = find_size1(inst_size, $2);
+ if (find_size_reg($4) != SIZE8)
+ error("Second register in logical shift must be byte size");
+ $$ = 2;
+ op[0] = shift_reg_opcode;
+ switch (size) {
+ case SIZE8: op[0] += 0; break;
+ case SIZE16: op[0] += 8; break;
+ case SIZE32: op[0] += 12; break;
+ }
+ op[1] = reg($2) * 16 + reg($4);
+ }
+| logical_shift_inst REG ',' '#' NUMBER {
+ size = find_size1(inst_size, $2);
+ $$ = 2;
+ if (shift_imm_opcode == -1)
+ error("NORM may not use a constant");
+ op[0] = shift_imm_opcode;
+ switch (size) {
+ case SIZE8: op[0] += 0; break;
+ case SIZE16: op[0] += 8; break;
+ case SIZE32: op[0] += 12; break;
+ }
+ switch (size) {
+ case SIZE8:
+ case SIZE16:
+ op[1] = reg($2) * 16 + imm_data4_unsigned($5);
+ break;
+ case SIZE32:
+ op[1] = (reg($2) / 2) * 32 + imm_data5_unsigned($5);
+ break;
+ }
+ }
+| no_opperand_inst {
+ $$ = num_op;
+ op[0] = opcode0;
+ op[1] = opcode1;
+ }
+
+| TRAP '#' NUMBER {
+ $$ = 2;
+ op[0] = 0xD6;
+ op[1] = 0x30 + imm_data4_unsigned($3);
+ }
+| CPL REG {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0x90 + size * 8;
+ op[1] = reg($2) * 16 + 10;
+ }
+| DA REG {
+ $$ = 2;
+ op[0] = 0x90;
+ op[1] = reg($2) * 16 + 8;
+ }
+| NEG REG {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0x90 + size * 8;
+ op[1] = reg($2) * 16 + 11;
+ }
+| SEXT REG {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0x90 + size * 8;
+ op[1] = reg($2) * 16 + 9;
+ }
+
+| rotate_inst REG ',' '#' NUMBER {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = rotate_opcode + size * 8;
+ op[1] = reg($2) * 16 + imm_data4_unsigned($5);
+ }
+
+
+| LEA REG ',' REG '+' expr {
+ if ($6 >= -128 && $6 <= 127) {
+ $$ = 3;
+ op[0] = 0x40;
+ op[1] = reg($2) * 16 + reg_indirect($4);
+ op[2] = ($6 >= 0) ? $6 : 256 + $6;
+ RELOC_ABS_FF(2, 0);
+ } else {
+ op[0] = 0x48;
+ op[1] = reg($2) * 16 + reg_indirect($4);
+ op[2] = ($6 >= 0) ? msb($6) : msb(65536 + $6);
+ op[3] = ($6 >= 0) ? lsb($6) : lsb(65536 + $6);
+ RELOC_ABS_FFFF(2, 0);
+ }
+ }
+| stack_inst WORD {
+ $$ = 3;
+ size = find_size0(inst_size);
+ op[0] = msb(stack_addr_opcode) + size * 8;
+ op[1] = lsb(stack_addr_opcode) + msb(direct_addr($2));
+ op[2] = lsb(direct_addr($2));
+ RELOC_ABS_07ff(1, 0);
+ }
+| stack_inst rlist {
+ $$ = 2;
+ if (inst_size != UNKNOWN && find_size0(inst_size) != rlist_size)
+ error("inst specifies different size than registers used");
+ op[0] = stack_reg_opcode + rlist_reg_bank * 64 + rlist_size * 8;
+ op[1] = rlist_bitmask;
+ }
+
+
+| MUL REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ op[0] = 0xE6;
+ op[1] = reg($2) * 16 + reg($4);
+ }
+| MULU REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ if (size == SIZE8) {
+ op[0] = 0xE0;
+ op[1] = reg($2) * 16 + reg($4);
+ } else {
+ op[0] = 0xE4;
+ op[1] = reg($2) * 16 + reg($4);
+ }
+ }
+| MUL REG ',' '#' expr {
+ $$ = 2;
+ size = find_size1(inst_size, $2);
+ op[0] = 0xE9;
+ op[1] = reg($2) + 8;
+ op[2] = msb(imm_data16($5));
+ op[3] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF(2, 0);
+ }
+| MULU REG ',' '#' expr {
+ size = find_size2(inst_size, $2, $4);
+ if (size == SIZE8) {
+ $$ = 3;
+ op[0] = 0xE8;
+ op[1] = reg($2) * 16;
+ op[2] = imm_data8($5);
+ RELOC_ABS_FF(2, 0);
+ } else {
+ $$ = 4;
+ op[0] = 0xE9;
+ op[1] = reg($2) * 16;
+ op[2] = msb(imm_data16($5));
+ op[3] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF(2, 0);
+ }
+ }
+| DIV REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ switch (size) {
+ case SIZE8:
+ error("Singed DIV can't be 8 bit size"); break;
+ case SIZE16:
+ op[0] = 0xE7;
+ op[1] = reg($2) * 16 + reg($4);
+ break;
+ case SIZE32:
+ op[0] = 0xEF;
+ op[1] = (reg($2) / 2) * 32 + reg($4);
+ break;
+ }
+ }
+| DIVU REG ',' REG {
+ $$ = 2;
+ size = find_size2(inst_size, $2, $4);
+ switch (size) {
+ case SIZE8:
+ op[0] = 0xE1;
+ op[1] = reg($2) * 16 + reg($4);
+ break;
+ case SIZE16:
+ op[0] = 0xE5;
+ op[1] = reg($2) * 16 + reg($4);
+ break;
+ case SIZE32:
+ op[0] = 0xED;
+ op[1] = (reg($2) / 2) * 32 + reg($4);
+ break;
+ }
+ }
+| DIV REG ',' '#' expr {
+ size = find_size1(inst_size, $2);
+ switch (size) {
+ case SIZE8:
+ error("Singed DIV can't be 8 bit size"); break;
+ case SIZE16:
+ $$ = 3;
+ op[0] = 0xE8;
+ op[1] = reg($2) * 16 + 11;
+ op[2] = imm_data8($5);
+ RELOC_ABS_FF(2, 0);
+ break;
+ case SIZE32:
+ $$ = 4;
+ op[0] = 0xE9;
+ op[1] = (reg($2) / 2) * 32 + 9;
+ op[2] = msb(imm_data16($5));
+ op[3] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF(2, 0);
+ break;
+ }
+ }
+| DIVU REG ',' '#' expr {
+ size = find_size1(inst_size, $2);
+ switch (size) {
+ case SIZE8:
+ $$ = 3;
+ op[0] = 0xE8;
+ op[1] = reg($2) * 16 + 1;
+ op[2] = imm_data8($5);
+ RELOC_ABS_FF(2, 0);
+ break;
+ case SIZE16:
+ $$ = 3;
+ op[0] = 0xE8;
+ op[1] = reg($2) * 16 + 3;
+ op[2] = imm_data8($5);
+ RELOC_ABS_FF(2, 0);
+ break;
+ case SIZE32:
+ $$ = 4;
+ op[0] = 0xE9;
+ op[1] = (reg($2) / 2) * 32 + 1;
+ op[2] = msb(imm_data16($5));
+ op[3] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF(2, 0);
+ break;
+ }
+ }
+| CALL '[' REG ']' {
+ $$ = 2;
+ op[0] = 0xC6;
+ op[1] = reg($3);
+ }
+| FCALL jmpaddr {
+ $$ = 4;
+ op[0] = 0xC4;
+ op[1] = ($2 >> 8) & 255;
+ op[2] = $2 & 255;
+ op[3] = ($2 >> 16) & 255;
+ }
+| FJMP jmpaddr {
+ $$ = 4;
+ op[0] = 0xD4;
+ op[1] = ($2 >> 8) & 255;
+ op[2] = $2 & 255;
+ op[3] = ($2 >> 16) & 255;
+ }
+| JMP '[' REG ']' {
+ $$ = 2;
+ op[0] = 0xD6;
+ op[1] = 0x70 + reg_indirect($3);
+ }
+| JMP '[' A '+' DPTR ']' {
+ $$ = 2;
+ op[0] = 0xD6;
+ op[1] = 0x46;
+ }
+| JMP '[' '[' REG '+' ']' ']' {
+ $$ = 2;
+ op[0] = 0xD6;
+ op[1] = 0x60 + reg_indirect($4);
+ }
+
+| JMP jmpaddr {
+ $$ = 3;
+ op[0] = 0xD5;
+ op[1] = msb(rel16(MEM_POS + $$, $2));
+ op[2] = lsb(rel16(MEM_POS + $$, $2));
+ RELOC_FFFF(MEM_POS+$$,1,0);
+ }
+
+| CALL jmpaddr {
+ $$ = 3;
+ op[0] = 0xC5;
+ op[1] = msb(rel16(MEM_POS + $$, $2));
+ op[2] = lsb(rel16(MEM_POS + $$, $2));
+ RELOC_FFFF(MEM_POS+$$,1,0);
+ }
+| branch_inst jmpaddr {
+ $$ = 2;
+ op[0] = branch_opcode;
+ op[1] = rel8(MEM_POS + $$, $2);
+ RELOC_FF(MEM_POS + $$, 1,0);
+ }
+| CJNE REG ',' expr ',' jmpaddr {
+ $$ = 4;
+ size = find_size1(inst_size, $2);
+ op[0] = 0xE2 + size * 8;
+ op[1] = reg($2) * 16 + msb(direct_addr($4));
+ op[2] = lsb(direct_addr($4));
+ op[3] = rel8(MEM_POS + $$, $6);
+ RELOC_ABS_07ff(1, 0);
+ RELOC_FF(MEM_POS + $$, 3,1);
+ }
+| CJNE REG ',' '#' expr ',' jmpaddr {
+ size = find_size1(inst_size, $2);
+ if (size == SIZE8) {
+ $$ = 4;
+ op[0] = 0xE3;
+ op[1] = reg($2) * 16;
+ op[2] = rel8(MEM_POS + $$, $7);
+ op[3] = imm_data8($5);
+ RELOC_ABS_FF(3, 0);
+ } else {
+ $$ = 5;
+ op[0] = 0xEB;
+ op[1] = reg($2) * 16;
+ op[2] = rel8(MEM_POS + $$, $7);
+ op[3] = msb(imm_data16($5));
+ op[4] = lsb(imm_data16($5));
+ RELOC_ABS_FFFF(3, 0);
+ }
+ }
+| CJNE '[' REG ']' ',' '#' expr ',' jmpaddr {
+ size = find_size0(inst_size);
+ if (size == SIZE8) {
+ $$ = 4;
+ op[0] = 0xE3;
+ op[1] = reg_indirect($3) * 16 + 8;
+ op[2] = rel8(MEM_POS + $$, $9);
+ op[3] = imm_data8($7);
+ RELOC_ABS_FF(3, 0);
+ } else {
+ $$ = 5;
+ op[0] = 0xEB;
+ op[1] = reg_indirect($3) * 16 + 8;
+ op[2] = rel8(MEM_POS + $$, $9);
+ op[3] = msb(imm_data16($7));
+ op[4] = lsb(imm_data16($7));
+ RELOC_ABS_FFFF(3, 0);
+ }
+ }
+| DJNZ REG ',' jmpaddr {
+ $$ = 3;
+ size = find_size1(inst_size, $2);
+ op[0] = 0x87 + size * 8;
+ op[1] = reg($2) * 16 + 8;
+ op[2] = rel8(MEM_POS + $$, $4);
+ RELOC_FF(MEM_POS+$$, 2, 0);
+ }
+
+
+| DJNZ WORD ',' jmpaddr {
+ $$ = 4;
+ size = find_size0(inst_size);
+ op[0] = 0xE2 + size * 8;
+ op[1] = msb(direct_addr($2)) + 8;
+ op[2] = lsb(direct_addr($2));
+ op[3] = rel8(MEM_POS + $$, $4);
+ RELOC_ABS_07ff(1, 0);
+ RELOC_FF(MEM_POS + $$, 3, 1)
+ }
+
+| JB bit ',' jmpaddr {
+ $$ = 4;
+ op[0] = 0x97;
+ op[1] = 0x80 + msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ op[3] = rel8(MEM_POS + $$, $4);
+ RELOC_ABS_03FF(1, 0);
+ RELOC_FF(MEM_POS + $$, 3, 1);
+ }
+
+| JBC bit ',' jmpaddr {
+ $$ = 4;
+ op[0] = 0x97;
+ op[1] = 0xC0 + msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ op[3] = rel8(MEM_POS + $$, $4);
+ RELOC_ABS_03FF(1, 0);
+ RELOC_FF(MEM_POS + $$, 3, 1);
+ }
+
+| JNB bit ',' jmpaddr {
+ $$ = 4;
+ op[0] = 0x97;
+ op[1] = 0xA0 + msb(bit_addr($2));
+ op[2] = lsb(bit_addr($2));
+ op[3] = rel8(MEM_POS + $$, $4);
+ RELOC_ABS_03FF(1, 0);
+ RELOC_FF(MEM_POS + $$, 3, 1);
+ }
+
+
+arith_inst:
+ ADD {arith_opcode = 0;}
+ | ADDC {arith_opcode = 1;}
+ | AND {arith_opcode = 5;}
+ | CMP {arith_opcode = 4;}
+ | MOV {arith_opcode = 8;}
+ | OR {arith_opcode = 6;}
+ | SUB {arith_opcode = 2;}
+ | SUBB {arith_opcode = 3;}
+ | XOR {arith_opcode = 7;}
+
+short_data_inst:
+ ADDS {short_opcode = 0xA0;}
+ | MOVS {short_opcode = 0xB0;}
+
+logical_shift_inst:
+ ASL {shift_reg_opcode = 0xC1; shift_imm_opcode = 0xD1;}
+ | ASR {shift_reg_opcode = 0xC2; shift_imm_opcode = 0xD2;}
+ | LSR {shift_reg_opcode = 0xC0; shift_imm_opcode = 0xD0;}
+ | NORM {shift_reg_opcode = 0xC3; shift_imm_opcode = -1;}
+
+rotate_inst:
+ RL {rotate_opcode = 0xD3;}
+ | RLC {rotate_opcode = 0xD7;}
+ | RR {rotate_opcode = 0xD0;}
+ | RRC {rotate_opcode = 0xD7;}
+
+stack_inst:
+ POP {stack_addr_opcode = 0x8710; stack_reg_opcode = 0x27;}
+ | POPU {stack_addr_opcode = 0x8700; stack_reg_opcode = 0x37;}
+ | PUSH {stack_addr_opcode = 0x8730; stack_reg_opcode = 0x07;}
+ | PUSHU {stack_addr_opcode = 0x8720; stack_reg_opcode = 0x17;}
+
+no_opperand_inst:
+ BKPT {num_op = 1; opcode0 = 255; opcode1 = 0;}
+ | NOP {num_op = 1; opcode0 = 0; opcode1 = 0;}
+ | RESET {num_op = 2; opcode0 = 0xD6; opcode1 = 0x10;}
+ | RET {num_op = 2; opcode0 = 0xD6; opcode1 = 0x80;}
+ | RETI {num_op = 2; opcode0 = 0xD6; opcode1 = 0x90;}
+
+branch_inst:
+ BCC {branch_opcode = 0xF0;}
+ | BCS {branch_opcode = 0xF1;}
+ | BEQ {branch_opcode = 0xF3;}
+ | BG {branch_opcode = 0xF8;}
+ | BGE {branch_opcode = 0xFA;}
+ | BGT {branch_opcode = 0xFC;}
+ | BL {branch_opcode = 0xF9;}
+ | BLE {branch_opcode = 0xFD;}
+ | BLT {branch_opcode = 0xFB;}
+ | BMI {branch_opcode = 0xF7;}
+ | BNE {branch_opcode = 0xF2;}
+ | BNV {branch_opcode = 0xF4;}
+ | BOV {branch_opcode = 0xF5;}
+ | BPL {branch_opcode = 0xF6;}
+ | BR {branch_opcode = 0xFE;}
+ | JZ {branch_opcode = 0xEC;}
+ | JNZ {branch_opcode = 0xEE;}
+
+
+
+%%
+
+
+int reg(int reg_spec)
+{
+ return reg_spec & 15;
+}
+
+int reg_indirect(int reg_spec)
+{
+ if (reg_spec & BYTE_REG)
+ error("Indirect addressing may not use byte registers");
+ if ((reg_spec & 15) > 7)
+ error("Only R0 through R7 may be used for indirect addr");
+ return reg_spec & 7;
+}
+
+int rel16(int pos, int dest)
+{
+ int rel;
+
+ if (!p3) return 0; /* don't bother unless writing code */
+ if (dest & (BRANCH_SPACING - 1))
+ error("Attempt to jump to unaligned location");
+ pos &= ~(BRANCH_SPACING - 1);
+ rel = (dest - pos) / BRANCH_SPACING;
+ if (rel < -32768 || rel > 32767)
+ error("Attempt to jump out of 16 bit relative range");
+ if (rel < 0) rel += 65536;
+ return rel;
+}
+
+int rel8(int pos, int dest)
+{
+ int rel;
+
+ if (!p3) return 0; /* don't bother unless writing code */
+ if (dest & (BRANCH_SPACING - 1))
+ error("Attempt to jump to unaligned location");
+ pos &= ~(BRANCH_SPACING - 1);
+ rel = (dest - pos) / BRANCH_SPACING;
+ if (rel < -128 || rel > 127)
+ error("Attempt to jump out of 16 bit relative range");
+ if (rel < 0) rel += 256;
+ return rel;
+}
+
+int msb(int value)
+{
+ return (value >> 8) & 255;
+}
+
+int lsb(int value)
+{
+ return value & 255;
+}
+
+int direct_addr(int value)
+{
+ char buf[250];
+
+ if (value < 0 || value > 2047) {
+ sprintf(buf, "illegal value (%d) for direct address", value);
+ error(buf);
+ }
+ return value;
+}
+
+int imm_data4_signed(int value)
+{
+ if (value < -8 || value > 7)
+ error("illegal 4 bit (signed) value");
+ if (value >= 0) return value;
+ else return (16 + value);
+}
+
+int imm_data4_unsigned(int value)
+{
+ if (value < 0 || value > 15)
+ error("illegal 4 bit (unsigned) value");
+ return value;
+}
+
+int imm_data5_unsigned(int value)
+{
+ if (value < 0 || value > 31)
+ error("illegal 5 bit (unsigned) value");
+ return value;
+}
+
+int imm_data8(int value)
+{
+ if (value < -128 || value > 255)
+ error("illegal 8 bit value");
+ if (value >= 0) return value;
+ else return (256 + value);
+}
+
+int imm_data16(int value)
+{
+ if (value < -32728 || value > 65535)
+ error("illegal 16 bit value");
+ if (value >= 0) return value;
+ else return (65536 + value);
+}
+
+int bit_addr(int value)
+{
+ if (value < 0 || value > 1023) {
+ fprintf(stderr, "bad bit addr of 0x%04X (%d dec)\n",
+ value, value);
+ error("illegal bit address");
+ }
+ return value;
+}
+
+
+int find_size_reg(int op1spec)
+{
+ int op1size=UNKNOWN;
+
+ if (op1spec & BYTE_REG) op1size = SIZE8;
+ if (op1spec & WORD_REG) op1size = SIZE16;
+ if (op1size == UNKNOWN)
+ error("Register without implied size");
+ return op1size;
+}
+
+int find_size0(int isize)
+{
+ if (isize == UNKNOWN)
+ error("Can't determine data size from instruction");
+ return isize;
+}
+
+int find_size1(int isize, int op1spec)
+{
+ int op1size=UNKNOWN;
+
+ if (op1spec & BYTE_REG) op1size = SIZE8;
+ if (op1spec & WORD_REG) op1size = SIZE16;
+ if (op1size == UNKNOWN)
+ error("Register without implied size");
+
+ if (isize == SIZE32 && op1size == SIZE16) return SIZE32;
+ if (isize == UNKNOWN) return op1size;
+ else {
+ if (isize != op1size)
+ error("data size of register and inst don't agree");
+ return isize;
+ }
+}
+
+int find_size2(int isize, int op1spec, int op2spec)
+{
+ int op1size=UNKNOWN, op2size=UNKNOWN;
+
+ if (op1spec & BYTE_REG) op1size = SIZE8;
+ if (op1spec & WORD_REG) op1size = SIZE16;
+ if (op1size == UNKNOWN)
+ error("Register without implied size");
+ if (op2spec & BYTE_REG) op2size = SIZE8;
+ if (op2spec & WORD_REG) op2size = SIZE16;
+ if (op1size == UNKNOWN)
+ error("Register without implied size");
+
+ if (op1size != op2size)
+ error("data sizes of two registers don't agree");
+ if (isize == UNKNOWN) return op1size;
+ else {
+ if (isize != op1size)
+ error("data size of registers and inst don't agree");
+ return isize;
+ }
+}
+
+int yyerror(char *s)
+{
+ if (yytext[0] >= 32) {
+ fprintf(stderr, "%s near '%s', line %d\n",
+ s, yytext, lineno);
+ } else {
+ fprintf(stderr, "%s, line %d\n", s, lineno - 1);
+ }
+ return 0;
+}
+
+void error(char *s)
+{
+ yyerror(s);
+ exit(1);
+}
+
+int yywrap()
+{
+ return 1;
+}
#include <xa.h>
bit b1, b2=1;
+code c1=0;
data d1, d2=2;
xdata x1, x2=3;
+extern bit be;
+extern code ce;
+extern data de;
+extern xdata xe;
+
#define BAUD_RATE 9600
#define OSC 20000000L /* Xtal frequency */
#define DIVIDER (OSC/(64L*BAUD_RATE))
void external_startup(void) {
+ xe=0;
_asm
mov.b _WDCON,#0 ;shut down the watchdog
mov.b _WFEED1,#0a5h
}
#endif
+#if 0
char getchar(void) {
char c;
RI0=0;
return c;
}
+#else
+char getchar();
+#endif
void puts(char *s) {
while (*s) {
}
void main(void) {
+ xe=getchar();
putchar('1');
putchar('2');
putchar('3');
}
} else {
aop->type=AOP_FAR;
- emitcode ("mov", "r0,#%s ; aopForSym:far", sym->rname);
+ emitcode ("mov.w", "r0,#%s ; aopForSym:far", sym->rname);
sprintf (aop->name[0], "[r0]");
if (size>2) {
sprintf (aop->name[1], "[r0+2]");
bool codePointer=IS_CODEPTR(operandType(left));
int size;
- printIc ("genPointerGet", ic, 1,1,0);
+ if (pi) {
+ printIc ("genPointerGet pi", ic, 1,1,0);
+ } else {
+ printIc ("genPointerGet", ic, 1,1,0);
+ }
if (!IS_PTR(operandType(left))) {
bailOut ("genPointerGet: pointer required");
int size;
char *instr;
bool trueOrFalse;
- symbol *jlbl, *tlbl;
+ symbol *jlbl, *tlbl=newiTempLabel(NULL);
operand *cond=IC_COND(ic);
emitcode (";", "genIfx(%d) cond=%s trueLabel:%s falseLabel:%s",
switch (AOP_TYPE(cond) )
{
case AOP_BIT:
- emitcode (trueOrFalse ? "jb" : "jnb", "%s,%05d$",
- AOP_NAME(cond)[0], jlbl->key+100);
+ emitcode (trueOrFalse ? "jnb" : "jb", "%s,%05d$",
+ AOP_NAME(cond)[0], tlbl->key+100);
+ emitcode ("jmp", "%05d$", jlbl->key+100);
+ emitcode ("", "%05d$:", tlbl->key+100);
return;
case AOP_REG:
case AOP_DIR:
case AOP_FAR:
case AOP_STK:
- tlbl=newiTempLabel(NULL);
if (size>1) {
instr="cmp.w";
} else {
} else {
/* we have to go by the storage class */
if (!SPEC_OCLS(etype)) {
+ ptrType=0; // hush the compiler
bailOut("genCast: unknown storage class");
} else {
ptrType = PTR_TYPE (SPEC_OCLS (etype));
case 0x11:
emitcode("mov", "%s,%s", AOP_NAME(result)[0], AOP_NAME(right)[0]);
return;
+ case 0x42:
+ emitcode("mov", "%s,%s", AOP_NAME(result)[0], AOP_NAME(right)[0]);
+ if (signedness) {
+ emitcode("sext", "%s", AOP_NAME(result)[1]);
+ } else {
+ emitcode("mov", "%s,#0", AOP_NAME(result)[1]);
+ }
+ return;
case 0x41:
case 0x21:
emitcode("mov", "r1l,%s", AOP_NAME(right)[0]);
if (signedness) {
emitcode("sext", "r1h");
} else {
- emitcode("mov", "rlh,#0");
+ emitcode("mov", "r1h,#0");
}
emitcode("mov", "%s,r1", AOP_NAME(result)[0]);
if (size==2)
// fall through: case 0x41
emitcode("sext", AOP_NAME(result)[1]);
return;
- case 14:
- case 12:
+ case 0x14:
+ case 0x12:
emitcode("mov", "r1,%s", AOP_NAME(right)[0]);
emitcode("mov", "%s,r1l", AOP_NAME(result)[0]);
return;
- case 24:
- emitcode("mov", "%s,%s", AOP_NAME(result)[0], AOP_NAME(right)[0]);
- return;
}
+ fprintf(stderr, "genCast: unknown size: %d:%d\n",
+ AOP_SIZE(result), AOP_SIZE(right));
bailOut("genCast: unknown size");
}
symbol *mainExists=newSymbol("main", 0);
mainExists->block=0;
- fprintf (of, "_errno\tsfr\t0x00; to keep the fp-lib's happy for now\n\n");
-
if ((mainExists=findSymWithLevel(SymbolTab, mainExists))) {
fprintf (of, "\t.area CSEG\t(CODE)\n");
fprintf (of, "__interrupt_vect:\n");
/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
static const char *_asmCmd[] =
{
- "xa_asm", "$l", "$3", "$1.xa", NULL
+ "xa_rasm", "$l", "$3", "$1.xa", NULL
};
/* Globals */
test-ucz80:
$(MAKE) inter-port-clean test-port PORT=ucz80
+# Helper rule for testing the xa51 port only(use ucSim simulator)
+test-xa51:
+ $(MAKE) inter-port-clean test-port PORT=xa51
+
### Helper rule for testing the host cc only
test-host:
$(MAKE) inter-port-clean test-port PORT=host
--- /dev/null
+# Port specification for the xa51 port running with uCsim
+
+# path to uCsim
+SXA_A = $(SDCC_DIR)/sim/ucsim/xa.src/sxa
+SXA_B = $(SDCC_DIR)/bin/sxa
+
+SXA = $(shell if [ -f $(SXA_A) ]; then echo $(SXA_A); else echo $(SXA_B); fi)
+
+SDCCFLAGS +=-mxa51 --lesspedantic -DREENTRANT=
+
+OBJEXT = .xa
+EXEEXT = .hex
+
+EXTRAS = fwk/lib/testfwk$(OBJEXT) $(PORTS_DIR)/$(PORT)/support$(OBJEXT)
+
+# Rule to link into .hex
+%$(EXEEXT): %$(OBJEXT) $(EXTRAS)
+ $(SDCC) $(SDCCFLAGS) $(EXTRAS) $<
+ mv fwk/lib/testfwk.hex $@
+ mv fwk/lib/testfwk.map $(@:.hex=.map)
+
+%$(OBJEXT): %.c
+ $(SDCC) $(SDCCFLAGS) -c $<
+
+# run simulator with 10 seconds timeout
+%.out: %$(EXEEXT) fwk/lib/timeout
+ mkdir -p `dirname $@`
+ -fwk/lib/timeout 10 $(SXA) -S in=/dev/null,out=$@ $< < $(PORTS_DIR)/xa51/uCsim.cmd >/dev/null || \
+ echo -e --- FAIL: \"timeout, simulation killed\" in $(<:.ihx=.c)"\n"--- Summary: 1/1/1: timeout >> $@
+ -grep -n FAIL $@ /dev/null || true
+
+fwk/lib/timeout: fwk/lib/timeout.c
+
+_clean:
+ rm -f fwk/lib/timeout fwk/lib/timeout.exe $(PORTS_DIR)/$(PORT)/*.rel $(PORTS_DIR)/$(PORT)/*.rst \
+ $(PORTS_DIR)/$(PORT)/*.lst $(PORTS_DIR)/$(PORT)/*.sym $(PORTS_DIR)/$(PORT)/*.xa temp.lnk
+
+
--- /dev/null
+/*-------------------------------------------------------------------------
+ support.c - startup for regression tests with uCsim
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include <tinibios.h>
+
+void
+_putchar (char c)
+{
+ _asm
+ mov.b r0l,[r7+2]
+ trap #0x0e
+ _endasm;
+}
+
+void
+_exitEmu (void)
+{
+ _asm
+ trap #0x0f
+ _endasm;
+}
+