From: johanknol Date: Thu, 7 Feb 2002 14:16:01 +0000 (+0000) Subject: xa51, work in progress X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=9d641f6056b707ba49ee139875d4a7b855b457c7;p=fw%2Fsdcc xa51, work in progress git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1902 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/as/xa51/Makefile b/as/xa51/Makefile index 0ed11c76..eab05d71 100644 --- a/as/xa51/Makefile +++ b/as/xa51/Makefile @@ -1,40 +1,34 @@ 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 *~ diff --git a/as/xa51/bigtest.xa b/as/xa51/bigtest.xa deleted file mode 100644 index a68df3c3..00000000 --- a/as/xa51/bigtest.xa +++ /dev/null @@ -1,141 +0,0 @@ - -;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] - - diff --git a/as/xa51/local_label.xa b/as/xa51/local_label.xa deleted file mode 100644 index 7d6f551d..00000000 --- a/as/xa51/local_label.xa +++ /dev/null @@ -1,40 +0,0 @@ -;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 - diff --git a/as/xa51/mt.xa b/as/xa51/mt.xa deleted file mode 100644 index dfa5ae9f..00000000 --- a/as/xa51/mt.xa +++ /dev/null @@ -1,1425 +0,0 @@ - -;$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 - - - - - - - - - diff --git a/as/xa51/paulmon2.xa b/as/xa51/paulmon2.xa deleted file mode 100644 index 6d26aba9..00000000 --- a/as/xa51/paulmon2.xa +++ /dev/null @@ -1,1941 +0,0 @@ -; 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 is waiting on serial port - ;C=clear if no , C=set if 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 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 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] - - - diff --git a/as/xa51/todo b/as/xa51/todo deleted file mode 100644 index 91f3496e..00000000 --- a/as/xa51/todo +++ /dev/null @@ -1,7 +0,0 @@ -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 - diff --git a/as/xa51/xa_asm.l b/as/xa51/xa_asm.l deleted file mode 100644 index 5366ec19..00000000 --- a/as/xa51/xa_asm.l +++ /dev/null @@ -1,326 +0,0 @@ -%{ -/* 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 -#include -#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];} - -%% diff --git a/as/xa51/xa_asm.y b/as/xa51/xa_asm.y deleted file mode 100644 index 4b87ea3f..00000000 --- a/as/xa51/xa_asm.y +++ /dev/null @@ -1,1330 +0,0 @@ -%{ -/* 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 - -#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; -} diff --git a/as/xa51/xa_dasm.c b/as/xa51/xa_dasm.c deleted file mode 100644 index b7d598bc..00000000 --- a/as/xa51/xa_dasm.c +++ /dev/null @@ -1,69 +0,0 @@ -/* 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 - -#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++; -} - - diff --git a/as/xa51/xa_main.c b/as/xa51/xa_main.c index 91c70944..31a77a83 100644 --- a/as/xa51/xa_main.c +++ b/as/xa51/xa_main.c @@ -17,6 +17,7 @@ /* adapted from the osu8asm project, 1995 */ /* http://www.pjrc.com/tech/osu8/index.html */ +#define D(x) x #include #include @@ -28,13 +29,18 @@ #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[]; @@ -48,6 +54,7 @@ char symbol_name[1000]; struct area_struct area[NUM_AREAS]; int current_area=AREA_CSEG; +char rel_line[2][132]; char *areaToString (int area) { switch (area) @@ -80,7 +87,13 @@ struct symbol * build_sym_list(char *thename) { 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); @@ -91,6 +104,7 @@ struct symbol * build_sym_list(char *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; @@ -99,7 +113,17 @@ struct symbol * build_sym_list(char *thename) 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; @@ -108,6 +132,7 @@ int assign_value(char *thename, int thevalue) if (!(strcasecmp(thename, p->name))) { p->value = thevalue; p->isdef = 1; + p->mode = mode; return (0); } p = p->next; @@ -116,7 +141,7 @@ int assign_value(char *thename, int thevalue) exit(1); } -int mk_bit(char *thename) +int mk_bit(char *thename, int area) { struct symbol *p; @@ -124,6 +149,7 @@ int mk_bit(char *thename) while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->isbit = 1; + p->area = area; return (0); } p = p->next; @@ -140,6 +166,7 @@ int mk_sfr(char *thename) while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->issfr = 1; + p->area = 0; return (0); } p = p->next; @@ -251,20 +278,21 @@ void print_symbol_table() 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) @@ -301,15 +329,27 @@ int is_reg(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 */ @@ -319,33 +359,72 @@ int is_def(char *thename) /* 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 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; inext) { + 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); + } } } @@ -453,12 +552,6 @@ void printVersion() { 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) @@ -498,17 +591,13 @@ 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 */ @@ -524,8 +613,8 @@ int main(int argc, char **argv) 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); } @@ -571,7 +660,6 @@ int main(int argc, char **argv) yyparse(); fclose(yyin); - hexout(0, 0, 1); /* flush and close intel hex file output */ return 0; } diff --git a/as/xa51/xa_main.h b/as/xa51/xa_main.h index 2daf30e3..d95f57a2 100644 --- a/as/xa51/xa_main.h +++ b/as/xa51/xa_main.h @@ -34,7 +34,9 @@ struct symbol { 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 */ @@ -47,6 +49,8 @@ struct target { struct area_struct { int start; int alloc_position; + int defsEmitted; + int size; }; extern int current_area; @@ -54,7 +58,7 @@ 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, @@ -66,7 +70,7 @@ enum { AREA_GSFINAL, AREA_HOME, AREA_SSEG, - NUM_AREAS + NUM_AREAS=AREA_SSEG }; extern struct area_struct area[NUM_AREAS]; @@ -77,13 +81,46 @@ extern int lineno; 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(); diff --git a/as/xa51/xa_rasm.l b/as/xa51/xa_rasm.l new file mode 100755 index 00000000..3f35c188 --- /dev/null +++ b/as/xa51/xa_rasm.l @@ -0,0 +1,326 @@ +%{ +/* 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 +#include +#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];} + +%% diff --git a/as/xa51/xa_rasm.y b/as/xa51/xa_rasm.y new file mode 100755 index 00000000..03ade71f --- /dev/null +++ b/as/xa51/xa_rasm.y @@ -0,0 +1,1505 @@ +%{ +/* 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 +#include +#include + +#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; +} diff --git a/device/examples/xa51/hello.c b/device/examples/xa51/hello.c index bbe19657..bd3e2b07 100755 --- a/device/examples/xa51/hello.c +++ b/device/examples/xa51/hello.c @@ -1,15 +1,22 @@ #include 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 @@ -55,6 +62,7 @@ void putchar(char c) { } #endif +#if 0 char getchar(void) { char c; @@ -64,6 +72,9 @@ char getchar(void) { RI0=0; return c; } +#else +char getchar(); +#endif void puts(char *s) { while (*s) { @@ -76,6 +87,7 @@ int kbhit(void) { } void main(void) { + xe=getchar(); putchar('1'); putchar('2'); putchar('3'); diff --git a/src/xa51/gen.c b/src/xa51/gen.c index 65f7b3f8..14190ca0 100755 --- a/src/xa51/gen.c +++ b/src/xa51/gen.c @@ -332,7 +332,7 @@ static asmop *aopForSym(symbol *sym, } } 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]"); @@ -1221,7 +1221,11 @@ static void genPointerGet (iCode * ic, iCode *pi) { 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"); @@ -1400,7 +1404,7 @@ static void genIfx (iCode * ic, iCode * popIc) { 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", @@ -1421,14 +1425,15 @@ static void genIfx (iCode * ic, iCode * popIc) { 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 { @@ -1632,6 +1637,7 @@ static void genCast (iCode * ic) { } 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)); @@ -1672,13 +1678,21 @@ static void genCast (iCode * ic) { 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) @@ -1686,15 +1700,14 @@ static void genCast (iCode * ic) { // 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"); } diff --git a/src/xa51/main.c b/src/xa51/main.c index 6db62f3c..60cb2d10 100755 --- a/src/xa51/main.c +++ b/src/xa51/main.c @@ -139,8 +139,6 @@ _xa51_genAssemblerPreamble (FILE * of) 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"); @@ -199,7 +197,7 @@ static const char *_linkCmd[] = /* $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 */ diff --git a/support/regression/Makefile b/support/regression/Makefile index 0d0ece9c..7a77a874 100644 --- a/support/regression/Makefile +++ b/support/regression/Makefile @@ -95,6 +95,10 @@ test-ds390: 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 diff --git a/support/regression/ports/xa51/spec.mk b/support/regression/ports/xa51/spec.mk new file mode 100755 index 00000000..39b98d7d --- /dev/null +++ b/support/regression/ports/xa51/spec.mk @@ -0,0 +1,38 @@ +# 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 + + diff --git a/support/regression/ports/xa51/support.c b/support/regression/ports/xa51/support.c new file mode 100755 index 00000000..fa3f3cd4 --- /dev/null +++ b/support/regression/ports/xa51/support.c @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + 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 + +void +_putchar (char c) +{ + _asm + mov.b r0l,[r7+2] + trap #0x0e + _endasm; +} + +void +_exitEmu (void) +{ + _asm + trap #0x0f + _endasm; +} + diff --git a/support/regression/ports/xa51/uCsim.cmd b/support/regression/ports/xa51/uCsim.cmd new file mode 100755 index 00000000..4023f209 --- /dev/null +++ b/support/regression/ports/xa51/uCsim.cmd @@ -0,0 +1 @@ +go