diff --git a/Machines/ATARI2600/VCS.H b/Machines/ATARI2600/VCS.H new file mode 100644 index 00000000..ecfbaafb --- /dev/null +++ b/Machines/ATARI2600/VCS.H @@ -0,0 +1,200 @@ +; VCS.H +; Version 1.05, 13/November/2003 + +VERSION_VCS = 105 + +; THIS IS A PRELIMINARY RELEASE OF *THE* "STANDARD" VCS.H +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; PLEASE DO *NOT* REDISTRIBUTE THIS FILE! +; +; This file defines hardware registers and memory mapping for the +; Atari 2600. It is distributed as a companion machine-specific support package +; for the DASM compiler. Updates to this file, DASM, and associated tools are +; available at at http://www.atari2600.org/dasm +; +; Many thanks to the original author(s) of this file, and to everyone who has +; contributed to understanding the Atari 2600. If you take issue with the +; contents, or naming of registers, please write to me (atari2600@taswegian.com) +; with your views. Please contribute, if you think you can improve this +; file! +; +; Latest Revisions... +; 1.05 13/NOV/2003 - Correction to 1.04 - now functions as requested by MR. +; - Added VERSION_VCS equate (which will reflect 100x version #) +; This will allow conditional code to verify VCS.H being +; used for code assembly. +; 1.04 12/NOV/2003 Added TIA_BASE_WRITE_ADDRESS and TIA_BASE_READ_ADDRESS for +; convenient disassembly/reassembly compatibility for hardware +; mirrored reading/writing differences. This is more a +; readability issue, and binary compatibility with disassembled +; and reassembled sources. Per Manuel Rotschkar's suggestion. +; 1.03 12/MAY/2003 Added SEG segment at end of file to fix old-code compatibility +; which was broken by the use of segments in this file, as +; reported by Manuel Polik on [stella] 11/MAY/2003 +; 1.02 22/MAR/2003 Added TIMINT($285) +; 1.01 Constant offset added to allow use for 3F-style bankswitching +; - define TIA_BASE_ADDRESS as $40 for Tigervision carts, otherwise +; it is safe to leave it undefined, and the base address will +; be set to 0. Thanks to Eckhard Stolberg for the suggestion. +; Note, may use -DLABEL=EXPRESSION to define TIA_BASE_ADDRESS +; - register definitions are now generated through assignment +; in uninitialised segments. This allows a changeable base +; address architecture. +; 1.0 22/MAR/2003 Initial release + + +;------------------------------------------------------------------------------- + +; TIA_BASE_ADDRESS +; The TIA_BASE_ADDRESS defines the base address of access to TIA registers. +; Normally 0, the base address should (externally, before including this file) +; be set to $40 when creating 3F-bankswitched (and other?) cartridges. +; The reason is that this bankswitching scheme treats any access to locations +; < $40 as a bankswitch. + + IFNCONST TIA_BASE_ADDRESS +TIA_BASE_ADDRESS = 0 + ENDIF + +; Note: The address may be defined on the command-line using the -D switch, eg: +; dasm.exe code.asm -DTIA_BASE_ADDRESS=$40 -f3 -v5 -ocode.bin +; *OR* by declaring the label before including this file, eg: +; TIA_BASE_ADDRESS = $40 +; include "vcs.h" + +; Alternate read/write address capability - allows for some disassembly compatibility +; usage ; to allow reassembly to binary perfect copies). This is essentially catering +; for the mirrored ROM hardware registers. + +; Usage: As per above, define the TIA_BASE_READ_ADDRESS and/or TIA_BASE_WRITE_ADDRESS +; using the -D command-line switch, as required. If the addresses are not defined, +; they defaut to the TIA_BASE_ADDRESS. + + IFNCONST TIA_BASE_READ_ADDRESS +TIA_BASE_READ_ADDRESS = TIA_BASE_ADDRESS + ENDIF + + IFNCONST TIA_BASE_WRITE_ADDRESS +TIA_BASE_WRITE_ADDRESS = TIA_BASE_ADDRESS + ENDIF + +;------------------------------------------------------------------------------- + + SEG.U TIA_REGISTERS_WRITE + ORG TIA_BASE_WRITE_ADDRESS + + ; DO NOT CHANGE THE RELATIVE ORDERING OF REGISTERS! + +VSYNC ds 1 ; $00 0000 00x0 Vertical Sync Set-Clear +VBLANK ds 1 ; $01 xx00 00x0 Vertical Blank Set-Clear +WSYNC ds 1 ; $02 ---- ---- Wait for Horizontal Blank +RSYNC ds 1 ; $03 ---- ---- Reset Horizontal Sync Counter +NUSIZ0 ds 1 ; $04 00xx 0xxx Number-Size player/missle 0 +NUSIZ1 ds 1 ; $05 00xx 0xxx Number-Size player/missle 1 +COLUP0 ds 1 ; $06 xxxx xxx0 Color-Luminance Player 0 +COLUP1 ds 1 ; $07 xxxx xxx0 Color-Luminance Player 1 +COLUPF ds 1 ; $08 xxxx xxx0 Color-Luminance Playfield +COLUBK ds 1 ; $09 xxxx xxx0 Color-Luminance Background +CTRLPF ds 1 ; $0A 00xx 0xxx Control Playfield, Ball, Collisions +REFP0 ds 1 ; $0B 0000 x000 Reflection Player 0 +REFP1 ds 1 ; $0C 0000 x000 Reflection Player 1 +PF0 ds 1 ; $0D xxxx 0000 Playfield Register Byte 0 +PF1 ds 1 ; $0E xxxx xxxx Playfield Register Byte 1 +PF2 ds 1 ; $0F xxxx xxxx Playfield Register Byte 2 +RESP0 ds 1 ; $10 ---- ---- Reset Player 0 +RESP1 ds 1 ; $11 ---- ---- Reset Player 1 +RESM0 ds 1 ; $12 ---- ---- Reset Missle 0 +RESM1 ds 1 ; $13 ---- ---- Reset Missle 1 +RESBL ds 1 ; $14 ---- ---- Reset Ball +AUDC0 ds 1 ; $15 0000 xxxx Audio Control 0 +AUDC1 ds 1 ; $16 0000 xxxx Audio Control 1 +AUDF0 ds 1 ; $17 000x xxxx Audio Frequency 0 +AUDF1 ds 1 ; $18 000x xxxx Audio Frequency 1 +AUDV0 ds 1 ; $19 0000 xxxx Audio Volume 0 +AUDV1 ds 1 ; $1A 0000 xxxx Audio Volume 1 +GRP0 ds 1 ; $1B xxxx xxxx Graphics Register Player 0 +GRP1 ds 1 ; $1C xxxx xxxx Graphics Register Player 1 +ENAM0 ds 1 ; $1D 0000 00x0 Graphics Enable Missle 0 +ENAM1 ds 1 ; $1E 0000 00x0 Graphics Enable Missle 1 +ENABL ds 1 ; $1F 0000 00x0 Graphics Enable Ball +HMP0 ds 1 ; $20 xxxx 0000 Horizontal Motion Player 0 +HMP1 ds 1 ; $21 xxxx 0000 Horizontal Motion Player 1 +HMM0 ds 1 ; $22 xxxx 0000 Horizontal Motion Missle 0 +HMM1 ds 1 ; $23 xxxx 0000 Horizontal Motion Missle 1 +HMBL ds 1 ; $24 xxxx 0000 Horizontal Motion Ball +VDELP0 ds 1 ; $25 0000 000x Vertical Delay Player 0 +VDELP1 ds 1 ; $26 0000 000x Vertical Delay Player 1 +VDELBL ds 1 ; $27 0000 000x Vertical Delay Ball +RESMP0 ds 1 ; $28 0000 00x0 Reset Missle 0 to Player 0 +RESMP1 ds 1 ; $29 0000 00x0 Reset Missle 1 to Player 1 +HMOVE ds 1 ; $2A ---- ---- Apply Horizontal Motion +HMCLR ds 1 ; $2B ---- ---- Clear Horizontal Move Registers +CXCLR ds 1 ; $2C ---- ---- Clear Collision Latches + +;------------------------------------------------------------------------------- + + SEG.U TIA_REGISTERS_READ + ORG TIA_BASE_READ_ADDRESS + + ; bit 7 bit 6 +CXM0P ds 1 ; $00 xx00 0000 Read Collision M0-P1 M0-P0 +CXM1P ds 1 ; $01 xx00 0000 M1-P0 M1-P1 +CXP0FB ds 1 ; $02 xx00 0000 P0-PF P0-BL +CXP1FB ds 1 ; $03 xx00 0000 P1-PF P1-BL +CXM0FB ds 1 ; $04 xx00 0000 M0-PF M0-BL +CXM1FB ds 1 ; $05 xx00 0000 M1-PF M1-BL +CXBLPF ds 1 ; $06 x000 0000 BL-PF ----- +CXPPMM ds 1 ; $07 xx00 0000 P0-P1 M0-M1 +INPT0 ds 1 ; $08 x000 0000 Read Pot Port 0 +INPT1 ds 1 ; $09 x000 0000 Read Pot Port 1 +INPT2 ds 1 ; $0A x000 0000 Read Pot Port 2 +INPT3 ds 1 ; $0B x000 0000 Read Pot Port 3 +INPT4 ds 1 ; $0C x000 0000 Read Input (Trigger) 0 +INPT5 ds 1 ; $0D x000 0000 Read Input (Trigger) 1 + +;------------------------------------------------------------------------------- + + SEG.U RIOT + ORG $280 + + ; RIOT MEMORY MAP + +SWCHA ds 1 ; $280 Port A data register for joysticks: + ; Bits 4-7 for player 1. Bits 0-3 for player 2. + +SWACNT ds 1 ; $281 Port A data direction register (DDR) +SWCHB ds 1 ; $282 Port B data (console switches) +SWBCNT ds 1 ; $283 Port B DDR +INTIM ds 1 ; $284 Timer output + +TIMINT ds 1 ; $285 + + ; Unused/undefined registers ($285-$294) + + ds 1 ; $286 + ds 1 ; $287 + ds 1 ; $288 + ds 1 ; $289 + ds 1 ; $28A + ds 1 ; $28B + ds 1 ; $28C + ds 1 ; $28D + ds 1 ; $28E + ds 1 ; $28F + ds 1 ; $290 + ds 1 ; $291 + ds 1 ; $292 + ds 1 ; $293 + +TIM1T ds 1 ; $294 set 1 clock interval +TIM8T ds 1 ; $295 set 8 clock interval +TIM64T ds 1 ; $296 set 64 clock interval +T1024T ds 1 ; $297 set 1024 clock interval + +;------------------------------------------------------------------------------- +; The following required for back-compatibility with code which does not use +; segments. + + SEG + +; EOF diff --git a/Machines/ATARI2600/macro.h b/Machines/ATARI2600/macro.h new file mode 100644 index 00000000..ce7b9a15 --- /dev/null +++ b/Machines/ATARI2600/macro.h @@ -0,0 +1,165 @@ +; MACRO.H +; Version 1.06, 3/SEPTEMBER/2004 + +VERSION_MACRO = 106 + +; +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; PLEASE DO *NOT* REDISTRIBUTE MODIFIED VERSIONS OF THIS FILE! +; +; This file defines DASM macros useful for development for the Atari 2600. +; It is distributed as a companion machine-specific support package +; for the DASM compiler. Updates to this file, DASM, and associated tools are +; available at at http://www.atari2600.org/dasm +; +; Many thanks to the people who have contributed. If you take issue with the +; contents, or would like to add something, please write to me +; (atari2600@taswegian.com) with your contribution. +; +; Latest Revisions... +; +; 1.06 03/SEP/2004 - nice revision of VERTICAL_BLANK (Edwin Blink) +; 1.05 14/NOV/2003 - Added VERSION_MACRO equate (which will reflect 100x version #) +; This will allow conditional code to verify MACRO.H being +; used for code assembly. +; 1.04 13/NOV/2003 - SET_POINTER macro added (16-bit address load) +; +; 1.03 23/JUN/2003 - CLEAN_START macro added - clears TIA, RAM, registers +; +; 1.02 14/JUN/2003 - VERTICAL_SYNC macro added +; (standardised macro for vertical synch code) +; 1.01 22/MAR/2003 - SLEEP macro added. +; - NO_ILLEGAL_OPCODES switch implemented +; 1.0 22/MAR/2003 Initial release + +; Note: These macros use illegal opcodes. To disable illegal opcode usage, +; define the symbol NO_ILLEGAL_OPCODES (-DNO_ILLEGAL_OPCODES=1 on command-line). +; If you do not allow illegal opcode usage, you must include this file +; *after* including VCS.H (as the non-illegal opcodes access hardware +; registers and require them to be defined first). + +; Available macros... +; SLEEP n - sleep for n cycles +; VERTICAL_SYNC - correct 3 scanline vertical synch code +; CLEAN_START - set machine to known state on startup +; SET_POINTER - load a 16-bit absolute to a 16-bit variable + +;------------------------------------------------------------------------------- +; SLEEP duration +; Original author: Thomas Jentzsch +; Inserts code which takes the specified number of cycles to execute. This is +; useful for code where precise timing is required. +; ILLEGAL-OPCODE VERSION DOES NOT AFFECT FLAGS OR REGISTERS. +; LEGAL OPCODE VERSION MAY AFFECT FLAGS +; Uses illegal opcode (DASM 2.20.01 onwards). + + MAC SLEEP ;usage: SLEEP n (n>1) +.CYCLES SET {1} + + IF .CYCLES < 2 + ECHO "MACRO ERROR: 'SLEEP': Duration must be > 1" + ERR + ENDIF + + IF .CYCLES & 1 + IFNCONST NO_ILLEGAL_OPCODES + nop 0 + ELSE + bit VSYNC + ENDIF +.CYCLES SET .CYCLES - 3 + ENDIF + + REPEAT .CYCLES / 2 + nop + REPEND + ENDM + +;------------------------------------------------------------------------------- +; VERTICAL_SYNC +; revised version by Edwin Blink -- saves bytes! +; Inserts the code required for a proper 3 scanline vertical sync sequence +; Note: Alters the accumulator + +; OUT: A = 0 + + MAC VERTICAL_SYNC + lda #%1110 ; each '1' bits generate a VSYNC ON line (bits 1..3) +.VSLP1 sta WSYNC ; 1st '0' bit resets Vsync, 2nd '0' bit exit loop + sta VSYNC + lsr + bne .VSLP1 ; branch until VYSNC has been reset + ENDM + +;------------------------------------------------------------------------------- +; CLEAN_START +; Original author: Andrew Davie +; Standardised start-up code, clears stack, all TIA registers and RAM to 0 +; Sets stack pointer to $FF, and all registers to 0 +; Sets decimal mode off, sets interrupt flag (kind of un-necessary) +; Use as very first section of code on boot (ie: at reset) +; Code written to minimise total ROM usage - uses weird 6502 knowledge :) + + MAC CLEAN_START + sei + cld + + ldx #0 + txa + tay +.CLEAR_STACK dex + txs + pha + bne .CLEAR_STACK ; SP=$FF, X = A = Y = 0 + + ENDM + +;------------------------------------------------------- +; SET_POINTER +; Original author: Manuel Rotschkar +; +; Sets a 2 byte RAM pointer to an absolute address. +; +; Usage: SET_POINTER pointer, address +; Example: SET_POINTER SpritePTR, SpriteData +; +; Note: Alters the accumulator, NZ flags +; IN 1: 2 byte RAM location reserved for pointer +; IN 2: absolute address + + MAC SET_POINTER +.POINTER SET {1} +.ADDRESS SET {2} + + LDA #<.ADDRESS ; Get Lowbyte of Address + STA .POINTER ; Store in pointer + LDA #>.ADDRESS ; Get Hibyte of Address + STA .POINTER+1 ; Store in pointer+1 + + ENDM + +;------------------------------------------------------- +; BOUNDARY byte# +; Original author: Denis Debro (borrowed from Bob Smith / Thomas) +; +; Push data to a certain position inside a page and keep count of how +; many free bytes the programmer will have. +; +; eg: BOUNDARY 5 ; position at byte #5 in page + +__DASM__TOTAL_FREE_MEMORY SET 0 +.FREE_BYTES SET 0 + MAC BOUNDARY + REPEAT 256 + IF <. % {1} = 0 + MEXIT + ELSE +.FREE_BYTES SET .FREE_BYTES + 1 + .byte $00 + ENDIF + REPEND +__DASM__TOTAL_FREE_MEMORY SET __DASM__TOTAL_FREE_MEMORY + .FREE_BYTES + ENDM + + +; EOF diff --git a/Machines/CHANNEL-F/CHANNELF.H b/Machines/CHANNEL-F/CHANNELF.H new file mode 100644 index 00000000..5765a9d8 --- /dev/null +++ b/Machines/CHANNEL-F/CHANNELF.H @@ -0,0 +1,35 @@ +; CHANNELF.H +; Version 1.00, 31/OCTOBER/2004 + +VERSION_CHANNELF = 100 + +; THIS IS A PRELIMINARY RELEASE OF *THE* "STANDARD" CHANNELF.H +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; PLEASE DO *NOT* REDISTRIBUTE THIS FILE! +; +; This file defines hardware registers and memory mapping for the +; Fairchild Channel-F. It is distributed as a companion machine-specific support package +; for the DASM compiler. Updates to this file, DASM, and associated tools are +; available at at http://www.atari2600.org/dasm +; +; Many thanks to the original author(s) of this file, and to everyone who has +; contributed to understanding the Channel-F. If you take issue with the +; contents, or naming of registers, please write to me (atari2600@taswegian.com) +; with your views. Please contribute, if you think you can improve this +; file! +; +; Latest Revisions... +; 1.00 31/OCT/2004 - initial release + + + +; Please contribute Channel-F header code to atari2600@taswegian.com + + +;------------------------------------------------------------------------------- +; The following required for back-compatibility with code which does not use +; segments. + + SEG + +; EOF diff --git a/Machines/CHANNEL-F/macro.h b/Machines/CHANNEL-F/macro.h new file mode 100644 index 00000000..f581c04b --- /dev/null +++ b/Machines/CHANNEL-F/macro.h @@ -0,0 +1,28 @@ +; MACRO.H for Channel F +; Version 1.00, 31/OCTOBER/2004 + +VERSION_MACRO = 100 + +; +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; PLEASE DO *NOT* REDISTRIBUTE MODIFIED VERSIONS OF THIS FILE! +; +; This file defines DASM macros useful for development for the Channel F. +; It is distributed as a companion machine-specific support package +; for the DASM compiler. Updates to this file, DASM, and associated tools are +; available at at http://www.atari2600.org/dasm +; +; Many thanks to the people who have contributed. If you take issue with the +; contents, or would like to add something, please write to me +; (atari2600@taswegian.com) with your contribution. +; +; Latest Revisions... +; +; 1.00 31/OCT/2004 - initial version + + + +; Please contribute Channel-F macros to atari2600@taswegian.com + + +; EOF diff --git a/Machines/CHANNEL-F/readme.txt b/Machines/CHANNEL-F/readme.txt new file mode 100644 index 00000000..d82e3dc8 --- /dev/null +++ b/Machines/CHANNEL-F/readme.txt @@ -0,0 +1,161 @@ + +This document describes some properties of DASM's +Fairchild F8 backend It does *not* describe how to +program the F8. + + +Processor selection +------------------- + +With DASM, the target CPU is selected with the PROCESSOR +directive inside the source file that should be assembled. +The F8 CPU is selected like this: + + processor f8 + processor F8 ; case insensitive + + + + +Expressions with parentheses +---------------------------- + +Some of DASM's backends, for instance the one for the 6502, +don't allow parentheses in expressions that are part of a +mnemonic's operand, because parentheses are used in the +6502's assembly language to denote indirect addressing. +Instead, you have to use brackets. + +This is not the case with the F8 backend. Both parentheses +and brackets can be used everywhere, so the following lines +are parsed and assembled correctly: + + as (2+2)*2 ; Assembles to $c8 + as [2+2]*2 ; Assembles to $c8 + + + + +Data definition directives +-------------------------- + +Since DS is an F8 instruction (decrement scratchpad register), +the DS directive isn't available anymore if DASM assembles +F8 code. Instead, use the RES directive, which works just like +the DS directive: + + ds.b 4,$33 ; Would assemble to $33 $33 $33 $33, + ; but isn't available in F8 mode + res.b 4,$33 ; Assembles to $33 $33 $33 $33 + +Of course RES.W and RES.L do exist aswell. + + +For source code compatibility with f8tool (another F8 assembler), some +additional data definition directives are available : DB, DW and DD. +These work just like DC.B, DC.W and DC.L: + + dc.b $f8 ; Assembles to $f8 + db $f8 ; Assembles to $f8 + + + + +Special register names +---------------------- + +For some of the special registers, multiple names are accepted: + + Register Accepted names + ------------------------------ + DC0 DC, DC0 + PC0 P0, PC0 + PC1 P, PC1 + J J, Any expression that evaluates to 9 + (This may seem strange, but J is really + just an alias for scratchpad register 9) + +The names DC, P0, P and J are standard syntax, the other forms +have been introduced for compatibility with other assemblers. + +Thus, the following lines assemble all correctly: + + lr h,dc ; Assembles to $11 + lr h,dc0 ; Assembles to $11 + lr p0,q ; Assembles to $0d + lr pc0,q ; Assembles to $0d + lr p,q ; Assembles to $09 + lr pc1,q ; Assembles to $09 + lr w,j ; Assembles to $1d + lr w,3*3 ; Assembles to $1d + + + + +Scratchpad register access +-------------------------- + +There are several ways to access scratchpad registers: + + Access mode Accepted syntax + --------------------------------------------------------------- + Direct access to registers 0..11 Any expression that + evaluates to 0..11 + + Access via ISAR S, (IS), any expression + that evaluates to 12 + + Access via ISAR, ISAR incremented I, (IS)+, any expression + that evaluates to 13 + + Access via ISAR, ISAR decremented D, (IS)-, any expression + that evaluates to 14 + +The (IS), (IS)+ and (IS)- forms are not standard syntax and have +been mainly introduced for compatibility with f8tool. + + +For some of the directly accessible scratchpad registers aliases exist: + + Register Alias name + -------------------------- + 9 J + 10 HU + 11 HL + +Originally, J was only used with the LR instruction when accessing the +flags, but since J is just an alias for register 9, J can also be used +in normal scratchpad register operations. + +The following lines assemble all correctly + + xs 2+2 ; Assembles to $e4 + xs s ; Assembles to $ec + xs (is) ; Assembles to $ec + xs 12 ; Assembles to $ec + xs i ; Assembles to $ed + xs (is)+ ; Assembles to $ed + xs 13 ; Assembles to $ed + xs d ; Assembles to $ee + xs (is)- ; Assembles to $ee + xs 14 ; Assembles to $ee + xs 9 ; Assembles to $e9 + xs j ; Assembles to $e9 + xs hu ; Assembles to $ea + xs hl ; Assembles to $eb + + + + +No instruction optimizations are done +------------------------------------- + +The assembler doesn't optimize instructions where a smaller +instruction could be used. It won't optimize between +OUT/OUTS, IN/INS and LI/LIS. + +For instance, the following line assembles to $20 $00, even +though the LIS instruction could be used, which would need +only one byte. + + li 0 ; Assembles to $20 $00 diff --git a/README.md b/README.md deleted file mode 100644 index c13a7dd5..00000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# dasm -Macro assembler with support for several 8-bit microprocessors diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..e2333cf1 --- /dev/null +++ b/README.txt @@ -0,0 +1,200 @@ + + DASM Version 2.20.10 + + DASM was created in 1988 by Matthew Dillon (dillon@apollo.backplane.com) + and modified in 1995 by Olaf 'Rhialto' Seibert (rhialto@polderland.nl), and + is now updated and maintained by Andrew Davie (atari2600@taswegian.com) + + DASM's homepage is http://www.atari2600.org/dasm + + DASM is freely re-distributable, and provided with full source-code to + allow recompilation for other target-platforms. This package may not be + sold on any media, or distributed in any way other than totally free. + + Directory structure... + + BIN\DOS Binary for DOS/Windows + BIN\Mac\Classic Binary for Mac Classic (2.20.07 onwards) + BIN\Mac\OSX Binary for Mac OSX (2.20.07 onwards) + BIN\Linux Binaries (static and dynamic) (2.20.09 onwards) + DOC Documentation and manuals + SRC DASM Source code + TEST Suite of test code + + This file (README.TXT) will always list the most recent updates for + the DASM disributable. + + +VERSION HISTORY + + 2.20.10 - Fairchild Channel F (processor F8) support added. Thanks to Thomas Mathys! + - Please review the readme file in the new F8 directory. + - There have been a LOT of code modifications to improve readability/maintainability. + - ONLY the DOS binary is updated in this release; if you are able to provide binaries for + other platforms, please send to me so I can update. + + 2.20.09 - various cleanups and code modifications. Switched from typedefs to actual type usage to allow + Linux compatibility (Linux had ulong defined). Various minor changes. + - Linux versions compiled by Brian Wilson. + + 2.20.08 - started to do some source code changes - I think. + - // comments changed/removed + - changed DOC files to text format. We may go to HTML soon, but Word is definitely + a thing of the past! + + 2.20.07 - (3rd posting, Mac OSX version included! Thanks Jeremy Penner) + + 2.20.07 - (2nd posting, Amiga Version included! Thanks, Peter Gordon) + + 2.20.07 - Rewrote symbol table sort to NOT use string functions + + - Removed '_fmode' code altogether + + - Conditional compilation around + + - Mac binary provided by Jason Rein + + - I appear to have misplaced the Amiga binary??? + + + 2.20.05 - modified the file open from using _fmode (what was that FOR?!) to a "wb" + (as suggested by ES and PG) + + - changed itoa(...) usage to sprintf (PG - Amiga) + + - changed _stricmp(...) to stricmp (again, PG - amiga) + + - fixed Symbol Table Dump so it outputs symbol table even if errors occur + + - symbol table now displays string symbols in string form, too + + - further modifications to code (removed REGISTER keywords). + + - AMIGA support (binary included! - thanks Peter Gordon) + + + + 2.20.04 - Significant reformatting of code, prelude to full documentation. + + - Internal error numbers now equated (more maintanable code). + + - Command-line switches now allow / as prefix (and -). + + - Divide by 0 (generated equates, etc.) now treated as an unrecoverable error. + + - Error messages now contain more information about the error, including + the source-line where possible. Message templates allow inclusion of select + data on error output. + + - reworking of the output data. Typically, the -v switch is now un-necessary + as the appropriate messages to allow you to find errors will be output. + Back compatibility with the -v options has been maintained, though there + may be a few minor changes. + + - Branch out of range errors now list the 'distance' to the branch. + + - Undefined symbols are now *always* listed in a separate table. If an + unresolved symbol causes an error, then the table will be automatically + displayed at the end of assembly. + + - new command-line switch -T# where # is 0 or 1 + 0 = sort symbol table alphabetically (default) + 1 = sort symbol table by address + If available memory precludes a sort, then the table will be output in a + non-sorted order. + + - code now in transient state between old and new formatting. More modular, but + still all over the place as far as consistency. It'll improve as we go along. + + + 2.20.02 - Inclusion of full (?) illegal opcode support using MNE6502.C by + John Saeger. + + 2.20.01 - This version combines the modifications made by Olaf in 1995 + into an official release, with minor additions. The source-code + is currently being commented and/or rewritten to make future + maintenance easier. + + For Olaf's changes, see the #ifdef'ed parts in DASM.DOC. + These modifications have now become a part of the main code-line + of DASM, so they are not optional. Documentation will be merged + in a later version. + + - Machine-specific support is now provided for Atari 2600. + Other machines may be added at later dates. + + - 6502/7 illegal opcodes NOP zp and LAX (zp),y added + + 2.12.15 Matt's ultimate release, updates a memory-allocation problem on + SPARC systems. This fix appears to have been fixed in Olaf's + version, so 2.12.14 (*not* 2.12.15) was used as the code-base + for 2.20.01 + + 2.12.14 Olaf's release, including many additions - many of which are + conditionally-compiled. + + +COMPILATION + + The source code assumes that integers are LONG WORDS. All expression + computation is carried out with 32 bit ints. Additionaly, the + correct implementation of STDIO functions is assumed (no translation). + + This code will compile with little or no modification on DOS, Amiga, + Mac and UNIX systems. + + +FEATURES + + -relatively fast + -processor selection (use same assembler for many processors) + -multi-pass (more than two passes if required) + -conditional assembly + -local labels (VERY local labels) + -macro capability (no stacking limit) + -symbolic expression capability + -addressing mode overides + -arbitrary number of named segments + -many pseudo-ops for repeat loops, data generation, etc.... + -automatic checksumming accessed via the '...' symbol. + + +PROCESSORS + + --------------- CURRENTLY SUPPORTED MICROPROCESSORS --------------- + + +6502: ORDER LSB,MSB A.b X.b Y.b RelAddr: .+ilen+offset +68705: ORDER MSB,LSB A.b X.b RelAddr: .+ilen+offset +6803/HD6303:ORDER MSB,LSB A.b B.b X.w RelAddr: .+ilen+offset +6811: ORDER MSB,LSB A.b B.b X.w Y.w RelAddr: .+ilen+offset + + +ADDRESSING MODES 6502 68705 6803 6811 +BYTES HD6303 + + 2 implied x x x x + 2 immediate.8 #byte x x x x + 3 immediate.16 #word x x + 2 byteaddr byte x x x x + 2 byteaddr,x byte,x x x x x + 2 byteaddr,y byte,y x x + 3 wordaddr word x x x x + 3 wordaddr,x word,x x x + 3 wordaddr,y word,y x + 2 relative byte x x x x + 2 ind.byte.x (byte,x) x + 2 ind.byte.y (byte),y x + 3 ind.word (word) x + 1 0,x [0],x x + 2 bitmod #no,badr x baseinst + 2*bitno + 3 bitbramod #no,badr,rel x baseinst + 2*bitno + +NOTE: HD6303 instruction extensions over the 6803 are: + AIM OIM EIM TIM XGDX SLP + +I believe the 6811 is a superset of the 6803. +For 6507 (Atari 2600) use 6502 as the selected processor. + + +;EOF diff --git a/doc/DASM.TXT b/doc/DASM.TXT new file mode 100644 index 00000000..49fa755c --- /dev/null +++ b/doc/DASM.TXT @@ -0,0 +1,750 @@ + + +DOCUMENTATION FOR DASM, a high level macro cross assembler for: + + -6502 (and 6507) + -68705 + -6803 + -HD6303 (extension of 6803) + -68HC11 + +DASM was created in 1988 by Matthew Dillon (dillon@apollo.backplane.com) +and modified in 1995 by Olaf 'Rhialto' Seibert (rhialto@polderland.nl), and +is now updated and maintained by Andrew Davie (atari2600@taswegian.com) + +DASM's homepage is http://www.atari2600.org/dasm + +DASM is freely re-distributable, and provided with full source-code to +allow recompilation for other target-platforms. + + +PREFACE FROM MATT: + + Over the last year my work has included writing software to drive small + single-chip microcomputers for various things (remote telemetry units, + for instance). I have had need to program quite a few different + processors over that time. + + At the beginning, I used an awful macro assembler running on an IBM-PC. + I *really* wanted to do it on my Amiga. Thus the writing of this + program. + + Feel free to suggest other similar processors for me to add to the list! + The processor type is specified with a pseudo-op (see below). This + assembler produces only binary output in one of three formats described + below. In general, one has a master assembly file which INCLUDEs all + the modules. + + Also provided is FTOHEX which converts an output file in one of the + three formats to an intel-hex format suitable for many intelligent + prom programmers (I have a GTEK). + + YES it's packed with features! + +FEATURES: + + -fast assembly + -supports several common 8 bit processor models (NOT 8086, thank god!) + -takes as many passes as needed + -automatic checksum generation, special symbol '...' + -several binary output formats available. Format 2 allows reverse + indexed origins. + -multiple segments, BSS segments (no generation), relocatable origin. + -expressions, as in C but [] is used instead of () for parenthesis. + (all expressions are computed with 32 bit integers) + -no real limitation on label size, label values are 32 bits. + -complex pseudo ops, repeat loops, macros, etc.... + + +PREFACE FROM ANDREW (APRIL/2003) + +The documentation is lagging a bit behind the modifications. Essentially the information contained herein is correct, but there have been minor changes to the formatting of output data. + +Please see the accompanying ‘README.TXT’ in the distributable root directory for a list of recent changes to the package. + + +COMMAND LINE: + + dasm srcfile [options] + + options: -f# select output format 1-3 (default 1, see below) + -oname select output file name (else a.out) + -lname select list file name (else none generated) + -Lname list file, containing all passes + -sname select symbol dump file (else none generated) + -v# select verboseness 0-4 (default 0, see below) + -d debug mode + -DSYMBOL predefine a symbol, set to 0 + -DSYMBOL=EXPRESSION predefine a symbol, set to exp + -MSYMBOL=EXPRESSION define label as in EQM (same as –D) + + -Idir search directory for include and incbin + -p# max number of passes + -P# max number of passes, with less checks + + -T# sort symbol table by (0 = alphabetic (default) + or (non-zero= address/value) + + Example: dasm master.asm -f2 -oout -llist -v3 -DVER=4 + +Note: A slash (/) or dash (-) must prefix options. + + +Return Value: + + The assembler will return 0 on successful compilation, 1 otherwise. + + +FORMAT OPTIONS: + + 1 (DEFAULT) + + The output file contains a two byte origin in LSB,MSB order, then + data until the end of the file. + + Restrictions: Any instructions which generate output (within an + initialized segment) must do so with an ascending PC. Initialized + segments must occur in ascending order. + + 2 RAS (Random Access Segment) + + The output file contains one or more hunks. Each hunk consists + of a 2 byte origin (LSB,MSB), 2 byte length (LSB,MSB), and that + number of data bytes. The hunks occur in the same order as + initialized segments in the assembly. There are no restrictions + to segment ordering (i.e. reverse indexed ORG statements are + allowed). The next hunk begins after the previous hunk's data, + until the end of the file. + + 3 RAW (Raw) + + The output file contains data only (format #1 without the 2 byte + header). Restrictions are the same as for format #1. + + Format 3 RAW (Raw format) + Same as format 1, but NO header origin is generated. You get + nothing but data. + +VERBOSE OPTIONS: + + 0 (default) + + Only warnings and errors are generated + + 1 + -Segment list information generated after each pass + -Include file names are displayed + -statistics on why the assembler is going to make another pass + R1,R2 reason code: R3 + where R1 is the number of times the assembler encountered + something requiring another pass to resolve. R2 is the + number of references to unknown symbols which occured in the + pass (but only R1 determines the need for another pass). R3 + is a BITMASK of the reasons why another pass is required. + See the end of this document for bit designations. + + 2 + mismatches between program labels and equates are displayed + on every pass (usually none occur in the first pass unless you + have re-declared a symbol name). + + displayed information for symbols: + ???? = unknown value + str = symbol is a string + eqm = symbol is an eqm macro + (r) = symbol has been referenced + (s) = symbol created with SET or EQM pseudo-op + + 3 + Unresolved and unreferenced symbols are displayed every pass + (unsorted, sorry) + + 4 + An entire symbol list is displayed every pass to STDOUT. + (unsorted, sorry) + + + +PROCESSOR MODEL: + + The processor model is chosen with the PROCESSOR pseudo-op and should + be the first thing you do in your assembly file. Different processor + models use different integer formats (see below). The word order does + not effect the headers in the output files (-f1 and -f2), which are + always LSB,MSB. The word ordering effects all address, word, and + long generation. + + Only one PROCESSOR pseudo-op may be declared in the entire assembly, + and should be the first thing encountered. + + -6502 LSB,MSB + -68HC11 MSB,LSB + -68705 MSB,LSB + -6803 MSB,LSB + -HD6303 MSB,LSB + -F8 ? + +SEGMENTS: + The SEG pseudo-op creates/sets the current segment. Each segment has + it's own origin and is optionally an 'uninitialized' segment. + Unitialized segments produce no output and have no restrictions. This + is useful for determining the size of a certain assembly sequence + without generating code, and for assigning RAM to labels. + + 'Initialized' segments produce output. The following should be + considered when generating roms: + + (1) The default fill character when using ORG (and format 1 or 3) to + skip forward is 00. This is a GLOBAL default and effects all + segments. See ORG. + + (2) The default fill character for DS is 00 and is independant of + the default fill character for ORG (see DS). + +GENERAL: + Most everything is recursive. You cannot have a macro DEFINITION + within a macro definition, but can nest macro calls, repeat loops, + and include files. + + The other major feature in this assembler is the SUBROUTINE pseudo-op, + which logically separates local labels (starting with a dot). This + allows you to reuse label names (for example, .1 .fail) rather than + think up crazy combinations of the current subroutine to keep it all + unique. + + Almost nothing need be resolved in pass 1. The assembler will make + multiple passes in an attempt to resolve the assembly (including just + one pass if everything is resolved immediately). + + +PSEUDOPS: + + INCLUDE "name" + + Include another assembly file. + +#if OlafIncbin + +[label] INCBIN "name" + + Include another file literally in the output. +#endif +#if OlafIncdir + + INCDIR "directory name" + + Add the given directory name to the list of places where + INCLUDE and INCBIN search their files. First, the names are + tried relative to the current directory, if that fails and + the name is not an absolute pathname, the list is tried. + You can optionally end the name with a /. AmigaDOS filename + conventions imply that two slashes at the + end of an INCDIR (dir//) indicates the parent directory, and + so does an INCLUDE /filename. + + The command-line option -Idir is equivalent to an INCDIR + directive placed before the source file. + + Currently the list is not cleared between passes, but each + exact directory name is added to the list only once. + This may change in subsequent releases. +#endif +[label] SEG[.U] name + + This sets the current segment, creating it if neccessary. If + a .U extension is specified on segment creation, the segment + is an UNINITIALIZED segment. The .U is not needed when going + back to an already created uninitialized segment, though it + makes the code more readable. + +[label] DC[.BWL] exp,exp,exp ... + + Declare data in the current segment. No output is generated if + within a .U segment. Note that the byte ordering for the + selected processor is used for each entry. + + The default size extension is a byte. +#if OlafByte + BYTE, WORD and LONG are synonyms for DC.B, DC.W and DC.L. +#endif + +[label] DS[.BWL] exp[,filler] + + declare space (default filler is 0). Data is not generated if + within an uninitialized segment. Note that the number of bytes + generated is exp * entrysize (1,2, or 4) + + The default size extension is a byte. + + Note that the default filler is always 0 (has nothing to do + with the ORG default filler). + +[label] DV[.BWL] eqmlabel exp,exp,exp.... + + This is equivalent to DC, but each exp in the list is passed + through the symbolic expression specified by the EQM label. + The expression is held in a special symbol dotdot '..' on each + call to the EQM label. + + See EQM below + +[label] HEX hh hh hh.. + + This sets down raw HEX data. Spaces are optional between bytes. + NO EXPRESSIONS are allowed. Note that you do NOT place a $ + in front of the digits. This is a short form for creating + tables compactly. Data is always layed down on a byte-by-byte + basis. + + Example: HEX 1A45 45 13254F 3E12 + + ERR + + Abort assembly. + +[label] ORG exp[,DefaultFillVal] + + This pseudop sets the current origin. You can also set the + global default fill character (a byte value) with this + pseudoop. NOTE that no filler is generated until the first + data-generating opcode/psueoop is encountered after this one. + Sequences like: + + org 0,255 + org 100,0 + org 200 + dc 23 + + will result in 200 zero's and a 23. This allows you to specify + some ORG, then change your mind and specify some other (lower + address) ORG without causing an error (assuming nothing is + generated inbetween). + + Normally, DS and ALIGN are used to generate specific filler + values. + +[label] RORG exp + + This activates the relocatable origin. All generated + addresses, including '.', although physically placed at the + true origin, will use values from the relocatable origin. + While in effect both the physical origin and relocatable origin + are updated. + + The relocatable origin can skip around (no limitations). The + relocatable origin is a function of the segment. That is, you + can still SEG to another segment that does not have a + relocatable origin activated, do other (independant) stuff + there, and then switch back to the current segment and continue + where you left off. + + PROCESSOR model + + do not quote. model is one of: 6502,6803,HD6303,68705,68HC11,F8 + Can only be executed once, and should be the first thing + encountered by the assembler. + + ECHO exp,exp,exp + + The expressions (which may also be strings), are echoed on the + screen and into the list file. + +[label] REND + + Deactivate the relocatable origin for the current segment. + Generation uses the real origin for reference. + +[label] ALIGN N[,fill] + + Align the current PC to an N byte boundry. The default + fill character is always 0, and has nothing to do with + the default fill character specifiable in an ORG. + +[label] SUBROUTINE name + + This isn't really a subroutine, but a boundry between sets of + temporary labels (which begin with a dot). Temporary label + names are unique within segments of code bounded by SUBROUTINE: + + CHARLIE subroutine + ldx #10 + .1 dex + bne .1 + BEN subroutine + ldx #20 + .qq dex + bne .qq + + Automatic temporary label boundries occur for each macro level. + Usually temporary labels are used in macros and within actual + subroutines (so you don't have to think up a thousand different + names) + + +symbol EQU exp +#if OlafAsgn +symbol = exp +#endif + + The expression is evaluated and the result assigned to the + symbol. + +#if OlafDotAssign + If this option is enabled, you can use the common idiom of + + . EQU . + 3 (or . = .+3) + + in other words, you can assign to "." (or "*" if OlafStar + is also enabled) instead of an ORG or RORG directive. + More formally, a directive of the form ". EQU expr" is + interpreted as if it were written " (R)ORG expr". + The RORG is used if a relocatable origin is already in effect, + otherwise ORG is used. Note that the first example is NOT + equivalent with "DS.B 3" when the rorg is in effect. +#endif + +symbol EQM exp + + The STRING representing the expression is assigned to the + symbol. Occurances of the label in later expressions causes + the string to be evaluated for each occurance. Also used in + conjuction with the DV psuedo-op. + +symbol SET exp + + Same as EQU, but the symbol may be reassigned later. + + MAC name + + Declare a macro. lines between MAC and ENDM are the macro. + You cannot recursively declare a macro. You CAN recursively + use a macro (reference a macro in a macro). No label is + allowed to the left of MAC or ENDM. + + Arguments passed to macros are referenced with: {#}. The first + argument passed to a macro would thus be {1}. You should + always use LOCAL labels (.name) inside macros which you use + more than once. {0} represents an EXACT substitution of the + ENTIRE argument line. + + ENDM + + end of macro def. NO LABEL ALLOWED ON THE LEFT! + + MEXIT + + Used in conjuction with conditionals. Exits the current macro + level. + +[label] IFCONST exp + + Is TRUE if the expression result is defined, FALSE otherwise + and NO error is generated if the expression is undefined. + +[label] IFNCONST exp + + Is TRUE if the expression result is undefined, FALSE otherwise + and NO error is generated if the expression is undefined. + +[label] IF exp + + Is TRUE if the expression result is defined AND non-zero. + Is FALSE if the expression result is defined AND zero. + Neither IF or ELSE will be executed if the expression result + is undefined. If the expression is undefined, another assembly + pass is automatically taken. +#if OlafPhase + If this happens, phase errors in the next pass only will not + be reported unless the verboseness is 1 or more. +#endif + +[label] ELSE + + ELSE the current IF. + +[label] ENDIF +[label] EIF + + Terminate an IF. ENDIF and EIF are equivalent. + +[label] REPEAT exp +[label] REPEND + + Repeat code between REPEAT/REPEND 'exp' times. + +#if DAD + if exp == 0, + the code repeats forever. exp is evaluated once. + + If exp == 0, the repeat loop is ignored. + If exp < 0, a warning “REPEAT parameter < 0 (ignored)” is generated and the repeat loop is ignored. +#endif + + Y SET 0 + REPEAT 10 + X SET 0 + REPEAT 10 + DC X,Y + X SET X + 1 + REPEND + Y SET Y + 1 + REPEND + + generates an output table: 0,0 1,0 2,0 ... 9,0 0,1 1,1 2,1 + ... 9,1, etc... + + Labels within a REPEAT/REPEND should be temporary labels with a + SUBROUTINE pseudo-op to keep them unique. + + The Label to the left of REPEND is assigned AFTER the loop + FINISHES. + + +[label] XXX[.force] operand + + XXX is some mnemonic, not necessarily three characters long. + The .FORCE optional extension is used to force specific + addressing modes (see below). + +[label] LIST ON or OFF + + Globally turns listing on or off, starting with the current + line. +#if OlafList + When you give LOCALON or LOCALOFF the effect is local to the + current macro or included file. For a line to be listed both + the global and local list switches must be on. +#endif + +#if OlafDotop + All pseudo-ops (and incidentally also the mnemonics) can be + prefixed with a . for compatibility with other assemblers. + So .IF is the same as IF. This works only because lone .FORCE + extensions are meaningless. +#endif + +#if OlafFreeFormat + The format of each input line is free: first all leading + spaces are discarded, and the first word is examined. If it + does not look like a directive or opcode (as known at that point), + it is taken as a label. This is sort-of nasty if you like labels + with names like END. + The two xxxFormat options are mutually exclusive. +#endif + +#if OlafHashFormat + With this option an initial # (after optional initial spaces) + turns the next word into a directive/opcode. + A ^ skips more spaces and makes the next word a label. +#endif + +GENERAL: + + The label will be set to the current ORG/RORG either before or after + a pseudo-op is executed. Most of the time, the label to the left of a + pseudo-op is the current ORG/RORG. The following pseudo-op's labels are + created AFTER execution of the pseudo-op: + + SEG, ORG, RORG, REND, ALIGN + +EXTENSIONS: + + FORCE extensions are used to force an addressing mode. In some cases, + you can optimize the assembly to take fewer passes by telling it the + addressing mode. Force extensions are also used with DS,DC, and DV + to determine the element size. NOT ALL EXTENSIONS APPLY TO ALL + PROCESSORS! + + example: lda.z charlie + + i -implied + ind -indirect word + 0 -implied + 0x -implied indexing (0,x) + 0y -implied indexing (0,y) + b -byte address + bx -byte address indexed x + by -byte address indexed y + w -word address + wx -word address indexed x + wy -word address indexed y + l -longword (4 bytes) (DS/DC/DV) + r -relative + u -uninitialized (SEG) + + First character equivalent substitutions: + + b z d (byte, zeropage, direct) + w e a (word, extended, absolute) + + +ASSEMBLER PASSES: + The assembler may have to make several passes through the source + code to resolve all generation. The number of passes is not + limited to two. Since this may result in an unexpected, verbose + option 2, 3, and 4 have been provided to allow determination of the + cause. The assembler will give up if it thinks it can't do the + assembly in *any* number of passes. + + Error reporting could be better.... + +#if OlafPasses + + The check if another pass might resolve the source is pretty good, but + not perfect. You can specify the maximum number of passes to do + (default -p10), and with the -P option you can override the normal check. + This allows the following contrived example to resolve in 12 passes: + + org 1 + repeat [[x < 11] ? [x-11]] + 11 + dc.b x + repend + x: + +#endif + +EXPRESSIONS: + [] may be used to group expressions. The precedense of operators + is the same as for the C language in almost all respects. Use + brackets [] when you are unsure. The reason () cannot be used to + group expressions is due to a conflict with the 6502 and other + assembly languages. +#if OlafBraKet + It is possible to use () instead of [] in expressions following + pseudo-ops, but not following mnemonics. So this works: + if target & (pet3001 | pet4001), but this doesn't: + lda #target & (pet3001 | pet4001). +#endif + + Some operators, such as ||, can return a resolved value even if + one of the expressions is not resolved. Operators are as follows: + + NOTE WELL! Some operations will result in non-byte values when a + byte value was wanted. For example: ~1 is NOT $FF, but + $FFFFFFFF. Preceding it with a < (take LSB of) will solve the + problem. ALL ARITHMETIC IS CARRIED OUT IN 32 BITS. The final + Result will be automatically truncated to the maximum handleable + by the particular machine language (usually a word) when applied + to standard mnemonics. + + prec UNARY + + 20 ~exp one's complement. + 20 -exp negation + 20 !exp not expression (returns 0 if exp non-zero, 1 if exp zero) + 20 exp take MSB byte of an expression + + BINARY + + 19 * multiplication + 19 / division + 19 % mod + 18 + addition + 18 - subtraction + 17 >>,<< shift right, shift left + 16 >,>= greater, greater equal + 16 <,<= smaller, smaller equal + 15 == equal to. Try to use this instead of = + 15 = exactly the same as == (exists compatibility) + 15 != not equal to + 14 & logical and + 13 ^ logical xor + 12 | logical or + 11 && left expression is true AND right expression is true + 10 || left expression is true OR right expression is true + 9 ? if left expression is true, result is right expression, + else result is 0. [10 ? 20] returns 20 + 8 [] group expressions + 7 , separate expressions in list (also used in + addressing mode resolution, BE CAREFUL! + + Note: The effect of the C conditional operator a ? b : c can be + had with [a ? b - c] + c. + + Constants: + + nnn decimal + 0nnn octal + %nnn binary + $nnn hex + 'c character + "cc.." string (NOT zero terminated if in DC/DS/DV) + [exp]d the constant expressions is evaluated and it's decimal + result turned into an ascii string. + + Symbols: + + ... -holds CHECKSUM so far (of actual-generated stuff) + .. -holds evaluated value in DV pseudo op + .name -represents a temporary symbol name. Temporary symbols + may be reused inside MACROS and between SUBROUTINES, but + may not be referenced across macros or across SUBROUTINEs. + . -current program counter (as of the beginning of the + instruction). + name -beginning with an alpha character and containing letters, + numbers, or '_'. Represents some global symbol name. +#if OlafStar + * -synonym for ., when not confused as an operator. +#endif +#if OlafDol + nnn$ -temporary label, much like .name, except that defining + a non-temporary label has the effect that SUBROUTINE + has on .name. They are unique within macros, like + .name. Note that 0$ and 00$ are distinct, as are 8$ + and 010$. + (mainly for compatibility with other assemblers.) +#endif + + +WHY codes: + Each bit in the WHY word (verbose option 1) is a reason (why + the assembler needs to do another pass), as follows: + + bit 0 expression in mnemonic not resolved + 1 - + 2 expression in a DC not resolved + 3 expression in a DV not resolved (probably in DV's EQM symbol) + 4 expression in a DV not resolved (could be in DV's EQM symbol) + 5 expression in a DS not resolved + 6 expression in an ALIGN not resolved + 7 ALIGN: Relocatable origin not known (if in RORG at the time) + 8 ALIGN: Normal origin not known (if in ORG at the time) + 9 EQU: expression not resolved + 10 EQU: value mismatch from previous pass (phase error) + 11 IF: expression not resolved + 12 REPEAT: expression not resolved + + 13 a program label has been defined after it has been + referenced (forward reference) and thus we need another + pass + 14 a program label's value is different from that of the + previous pass (phase error) + + Certain errors will cause the assembly to abort immediately, others + will wait until the current pass is other. The remaining allow another + pass to occur in the hopes the error will fix itself. + + +VERSIONS: + + V2.12 + -Fixed macro naming bug (macros wouldn't work if the name after + the 'mac' was in upper case). + + V2.11 + -Fixed exp bug, exp MSB (it used to + be reversed). + -Fixed many bugs in macros and other things + -Added automatic checksumming ... no more doing checksums manually! + -Added several new processors, including 6502. + -Source is now 16/32 bit int compatible, and will compile on an + IBM-PC (the ultimate portability test) + + V2.01 + + -can now have REPEAT/REPEND's within macros + -fill field for DS.W is a word (used to be a byte fill) + -fill field for DS.L is a long (used to be a byte fill) + + diff --git a/doc/FTOHEX.TXT b/doc/FTOHEX.TXT new file mode 100644 index 00000000..dfda0439 --- /dev/null +++ b/doc/FTOHEX.TXT @@ -0,0 +1,17 @@ +FTOHEX Convert assembly output file to INTEL-HEX format suitable for, say, +a GTEK prom programmer. + + FTOHEX format infile outfile + +Example: + DASM -f2 example.asm -oram:example.out + FTOHEX 2 ram:example.out ram:example.hex + + This program converts and output file generated by DASM to the Intel + hex-ascii format. You must specify the format you used when you + assembled the source for FTOHEX to properly read the out file. + Generally format 2 is used for assembly (see DASM.DOC) as this + generates the smallest hex file. + + + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..24fe08f7 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,35 @@ + +# DASM -small systems cross assembler +# DASM -small systems cross assembler. The source is compilable on +# Amiga's, UNIX systems, and any other system with ISO-C compiler. +# (C)Copyright 1988-1989 Matthew Dillon, All Rights Reserved. +# +# Modifications Copyright 1995 by Olaf Seibert. All Rights Reserved. + +GOPTIM= -O3 +GWARN= -ansi -pedantic -Wall -Wstrict-prototypes +GDB= # -g +#CC= gcc $(GDB) $(GOPTIM) $(GWARN) -Dstricmp=strcasecmp +#CC= dcc +CFLAGS= + +OBJS= main.o ops.o globals.o exp.o symbols.o \ + mne6303.o mne6502.o mne68705.o mne6811.o mnef8.o +SRCS= main.c ops.c globals.c exp.c symbols.c \ + mne6303.c mne6502.c mne68705.c mne6811.c mnef8.o + +all: dasm ftohex + +dasm: $(OBJS) + $(CC) $(OBJS) -o dasm + +ftohex: ftohex.o + $(CC) ftohex.o -o ftohex + +example: + dasm example.asm -oram:example.out -lram:example.list -f2 + ftohex 2 ram:example.out ram:example.hex + +obj: $(OBJS) + +$(OBJS): asm.h diff --git a/src/Makefile.mak b/src/Makefile.mak new file mode 100644 index 00000000..8a703b84 --- /dev/null +++ b/src/Makefile.mak @@ -0,0 +1,89 @@ +# +# DASM Assembler +# Portions of this code are Copyright (C)1988 Matthew Dillon +# and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie +# +# 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# DASM -small systems cross assembler +# DASM -small systems cross assembler. The source is compilable on +# Amiga's, UNIX systems, and any other system with ISO-C compiler. +# (C)Copyright 1988-1989 Matthew Dillon, All Rights Reserved. +# +# Modifications Copyright 1995 by Olaf Seibert. All Rights Reserved. + + + +#GOPTIM= -O3 +#GWARN= -ansi -pedantic -Wall -Wstrict-prototypes +GDB= # -g +#CC= gcc $(GDB) $(GOPTIM) $(GWARN) +CC= cl +CFLAGS= +# /O2 /WX +CFLAGS= /W0 + +OBJS= main.o \ + ops.o \ + globals.o \ + exp.o \ + symbols.o \ + mne6303.o \ + mne6502.o \ + mne68705.o \ + mne6811.o \ + mnef8.o + +SRCS= main.c ops.c globals.c exp.c symbols.c \ + mne6303.c mne6502.c mne68705.c mne6811.c mnef8.c + + +.c.o: + +all: dasm #ftohex + +dasm: + $(CC) $(CFLAGS) $(SRCS) /o..\bin\DOS\dasm.exe + +ftohex: ftohex.o + $(CC) ftohex.o -oftohex + +example: + dasm example.asm -oram:example.out -lram:example.list -f2 + ftohex 2 ram:example.out ram:example.hex + +obj: $(OBJS) + + + +$(OBJS): asm.h + + +DOS: $(OBJS) + $(DOS_CC) $(CFLAGS) $(SRCS) -odasm.exe + +AMIGA: $(OBJS) + $(DOS_CC) $(CFLAGS) $(SRCS) -odasm.exe + +LINUX: $(OBJS) + $(DOS_CC) $(CFLAGS) $(SRCS) -odasm.exe + +MAC_CLASSIC: $(OBJS) + $(DOS_CC) $(CFLAGS) $(SRCS) -odasm.exe + +MAC_OSX: $(OBJS) + $(DOS_CC) $(CFLAGS) $(SRCS) -odasm.exe + diff --git a/src/asm.h b/src/asm.h new file mode 100644 index 00000000..d2b1261b --- /dev/null +++ b/src/asm.h @@ -0,0 +1,434 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + * ASM65.H + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + * Modifications Copyright 1995 by Olaf Seibert. All Rights Reserved. + * + * Structures and definitions + */ + +#include +#include +#include + +#define OlafFreeFormat 0 /* Decide on looks of word if it is opcode */ +#define OlafHashFormat 1 /* Decide on # and ^ if it is an opcode */ + +#if OlafHashFormat && OlafFreeFormat +#error This cannot be! +#endif + +#define DAD + +#ifdef DAD + +#ifndef bool +#define bool int +#define false 0 +#define true 1 +#endif + + +enum FORMAT +{ + FORMAT_DEFAULT = 1, + FORMAT_RAS, + FORMAT_RAW, + FORMAT_MAX +}; + + +#define MAX_SYM_LEN 1024 + + enum ASM_ERROR_EQUATES + { + ERROR_NONE = 0, + ERROR_COMMAND_LINE, /* Check format of command-line */ + ERROR_FILE_ERROR, /* Unable to open file */ + ERROR_NOT_RESOLVABLE, /* Source is not resolvable */ + ERROR_TOO_MANY_PASSES, /* Too many passes - something wrong */ + + ERROR_SYNTAX_ERROR, /* 0 */ + ERROR_EXPRESSION_TABLE_OVERFLOW, /* 1 */ + ERROR_UNBALANCED_BRACES, /* 2 */ + ERROR_DIVISION_BY_0, /* 3 */ + ERROR_UNKNOWN_MNEMONIC, /* 4 */ + ERROR_ILLEGAL_ADDRESSING_MODE, /* 5 */ + ERROR_ILLEGAL_FORCED_ADDRESSING_MODE, /* 6 */ + ERROR_NOT_ENOUGH_ARGUMENTS_PASSED_TO_MACRO, /* 7 */ + ERROR_PREMATURE_EOF, /* 8 */ + ERROR_ILLEGAL_CHARACTER, /* 9 */ + ERROR_BRANCH_OUT_OF_RANGE, /* 10 */ + ERROR_ERR_PSEUDO_OP_ENCOUNTERED, /* 11 */ + ERROR_ORIGIN_REVERSE_INDEXED, /* 12 */ + ERROR_EQU_VALUE_MISMATCH, /* 13 */ + ERROR_ADDRESS_MUST_BE_LT_100, /* 14 */ + ERROR_ILLEGAL_BIT_SPECIFICATION, /* 15 */ + ERROR_NOT_ENOUGH_ARGS, /* 16 */ + ERROR_LABEL_MISMATCH, /* 17 */ + ERROR_VALUE_UNDEFINED, /* 18 */ + ERROR_PROCESSOR_NOT_SUPPORTED, /* 20 */ + ERROR_REPEAT_NEGATIVE, /* 21 */ + ERROR_BADERROR, /* 22 */ + ERROR_ONLY_ONE_PROCESSOR_SUPPORTED, /* Only allow one type of processor */ + ERROR_BAD_FORMAT, /* Bad format specifier */ + + /* F8 support... */ + + ERROR_VALUE_MUST_BE_1_OR_4, /* 25 */ + ERROR_VALUE_MUST_BE_LT_10, /* 26 */ + ERROR_VALUE_MUST_BE_LT_8, /* 27 */ + ERROR_VALUE_MUST_BE_LT_F, /* 28 */ + ERROR_VALUE_MUST_BE_LT_10000, /* 29 */ + ERROR_ILLEGAL_OPERAND_COMBINATION, /* 30 */ + + + + }; + + typedef struct ERRORSTRUCT + { + int nErrorType; /* ASM_ERROR_EQUATES value */ + bool bFatal; /* 0 = OK, non-zero = cannot continue compilation */ + char *sDescription; /* Error message */ + + } ERROR_DEFINITION; + + + enum REASON_CODES + { + REASON_MNEMONIC_NOT_RESOLVED = 1 << 0, + REASON_OBSCURE = 1 << 1, /* fix this! */ + REASON_DC_NOT_RESOVED = 1 << 2, + REASON_DV_NOT_RESOLVED_PROBABLY = 1 << 3, + REASON_DV_NOT_RESOLVED_COULD = 1 << 4, + REASON_DS_NOT_RESOLVED = 1 << 5, + REASON_ALIGN_NOT_RESOLVED = 1 << 6, + REASON_ALIGN_RELOCATABLE_ORIGIN_NOT_KNOWN = 1 << 7, + REASON_ALIGN_NORMAL_ORIGIN_NOT_KNOWN = 1 << 8, + REASON_EQU_NOT_RESOLVED = 1 << 9, + REASON_EQU_VALUE_MISMATCH = 1 << 10, + REASON_IF_NOT_RESOLVED = 1 << 11, + REASON_REPEAT_NOT_RESOLVED = 1 << 12, + REASON_FORWARD_REFERENCE = 1 << 13, + REASON_PHASE_ERROR = 1 << 14 + }; + + +#endif + +#define MNEMONIC struct _MNE +#define MACRO struct _MACRO +#define INCFILE struct _INCFILE +#define REPLOOP struct _REPLOOP +#define IFSTACK struct _IFSTACK +#define SEGMENT struct _SEGMENT +#define SYMBOL struct _SYMBOL +#define STRLIST struct _STRLIST + +#define DEFORGFILL 255 +#define SHASHSIZE 1024 +#define MHASHSIZE 1024 +#define SHASHAND 0x03FF +#define MHASHAND 0x03FF +#define ALLOCSIZE 16384 +#define MAXMACLEVEL 32 +#define TAB 9 + + + enum ADDRESS_MODES { + AM_IMP, /* implied */ + AM_IMM8, /* immediate 8 bits */ + AM_IMM16, /* immediate 16 bits */ + AM_BYTEADR, /* address 8 bits */ + AM_BYTEADRX, /* address 16 bits */ + AM_BYTEADRY, /* relative 8 bits */ + AM_WORDADR, /* index x 0 bits */ + AM_WORDADRX, /* index x 8 bits */ + AM_WORDADRY, /* index x 16 bits */ + AM_REL, /* bit inst. special */ + AM_INDBYTEX, /* bit-bra inst. spec. */ + AM_INDBYTEY, /* index y 0 bits */ + AM_INDWORD, /* index y 8 bits */ + AM_0X, /* index x 0 bits */ + AM_0Y, /* index y 0 bits */ + AM_BITMOD, /* ind addr 8 bits */ + AM_BITBRAMOD, /* ind addr 16 bits */ + + AM_SYMBOL, + AM_EXPLIST, + AM_LONG, + AM_BSS, + + NUMOC + }; + +#define AF_IMP ( 1L << AM_IMP ) +#define AF_IMM8 ( 1L << AM_IMM8 ) +#define AF_IMM16 ( 1L << AM_IMM16 ) +#define AF_BYTEADR ( 1L << AM_BYTEADR ) +#define AF_BYTEADRX ( 1L << AM_BYTEADRX ) +#define AF_BYTEADRY ( 1L << AM_BYTEADRY ) +#define AF_WORDADR ( 1L << AM_WORDADR ) +#define AF_WORDADRX ( 1L << AM_WORDADRX ) +#define AF_WORDADRY ( 1L << AM_WORDADRY ) +#define AF_REL ( 1L << AM_REL ) +#define AF_INDBYTEX ( 1L << AM_INDBYTEX ) +#define AF_INDBYTEY ( 1L << AM_INDBYTEY ) +#define AF_INDWORD ( 1L << AM_INDWORD ) +#define AF_0X ( 1L << AM_0X ) +#define AF_0Y ( 1L << AM_0Y ) +#define AF_BITMOD ( 1L << AM_BITMOD ) +#define AF_BITBRAMOD ( 1L << AM_BITBRAMOD ) + +#define AM_BYTE AM_BYTEADR +#define AM_WORD AM_WORDADR + + + +STRLIST { + STRLIST *next; + char buf[4]; +}; + +#define STRLISTSIZE 4 + +#define MF_IF 0x04 +#define MF_MACRO 0x08 +#define MF_MASK 0x10 /* has mask argument (byte) */ +#define MF_REL 0x20 /* has rel. address (byte) */ +#define MF_IMOD 0x40 /* instruction byte mod. */ +#define MF_ENDM 0x80 /* is v_endm */ + +MNEMONIC { + MNEMONIC *next; /* hash */ + void (*vect)(char *, MNEMONIC *); /* dispatch */ + char *name; /* actual name */ + unsigned char flags; /* special flags */ + unsigned long okmask; + unsigned int opcode[NUMOC]; /* hex codes, byte or word (>xFF) opcodes */ +}; + +MACRO { + MACRO *next; + void (*vect)(char *, MACRO *); + char *name; + unsigned char flags; + STRLIST *strlist; +}; + +#define INF_MACRO 0x01 +#define INF_NOLIST 0x02 + +INCFILE { + INCFILE *next; /* previously pushed context */ + char *name; /* file name */ + FILE *fi; /* file handle */ + unsigned long lineno; /* line number in file */ + unsigned char flags; /* flags (macro) */ + + /* Only if Macro */ + + STRLIST *args; /* arguments to macro */ + STRLIST *strlist; /* current string list */ + unsigned long saveidx; /* save localindex */ + unsigned long savedolidx; /* save localdollarindex */ + +}; + +#define RPF_UNKNOWN 0x01 /* value unknown */ + +REPLOOP { + REPLOOP *next; /* previously pushed context */ + unsigned long count; /* repeat count */ + unsigned long seek; /* seek to top of repeat */ + unsigned long lineno; /* line number of line before */ + INCFILE *file; /* which include file are we in*/ + unsigned char flags; +}; + +#define IFF_UNKNOWN 0x01 /* value unknown */ +#define IFF_BASE 0x04 + +IFSTACK { + IFSTACK *next; /* previous IF */ + INCFILE *file; /* which include file are we in*/ + unsigned char flags; + unsigned char xtrue; /* 1 if true, 0 if false */ + unsigned char acctrue;/* accumulatively true (not incl this one) */ +}; + +#define SF_UNKNOWN 0x01 /* ORG unknown */ +#define SF_REF 0x04 /* ORG referenced */ +#define SF_BSS 0x10 /* uninitialized area (U flag) */ +#define SF_RORG 0x20 /* relocatable origin active */ + +SEGMENT { + SEGMENT *next; /* next segment in segment list */ + char *name; /* name of segment */ + unsigned char flags; /* for ORG */ + unsigned char rflags; /* for RORG */ + unsigned long org; /* current org */ + unsigned long rorg; /* current rorg */ + unsigned long initorg; + unsigned long initrorg; + unsigned char initflags; + unsigned char initrflags; +}; + +#define SYM_UNKNOWN 0x01 /* value unknown */ +#define SYM_REF 0x04 /* referenced */ +#define SYM_STRING 0x08 /* result is a string */ +#define SYM_SET 0x10 /* SET instruction used */ +#define SYM_MACRO 0x20 /* symbol is a macro */ +#define SYM_MASREF 0x40 /* master reference */ + +SYMBOL { + SYMBOL *next; /* next symbol in hash list */ + char *name; /* symbol name or string if expr. */ + char *string; /* if symbol is actually a string */ + unsigned char flags; /* flags */ + unsigned char addrmode; /* addressing mode (expressions) */ + unsigned long value; /* current value */ + unsigned int namelen; /* name length */ +}; + +extern SYMBOL *SHash[]; +extern MNEMONIC *MHash[]; +extern INCFILE *pIncfile; +extern REPLOOP *Reploop; +extern SEGMENT *Seglist; +extern IFSTACK *Ifstack; + +extern SEGMENT *Csegment; /* current segment */ +extern char *Av[]; +extern char Avbuf[]; +/*extern unsigned int Adrbytes[];*/ +extern unsigned int Cvt[]; +extern MNEMONIC Ops[]; +extern unsigned int Opsize[]; +extern int Mnext; /* mnemonic extension */ +extern unsigned int Mlevel; + +extern bool bTrace; +extern bool Xdebug; +extern unsigned char MsbOrder; +extern unsigned char Outputformat; +extern unsigned long Redo_why; + +extern int Redo; +extern int Redo_eval; + +extern unsigned long Redo_if; +extern unsigned long Localindex, Lastlocalindex; +extern unsigned long Localdollarindex, Lastlocaldollarindex; +extern int F_format; +extern unsigned char F_verbose; +extern char *F_outfile; +extern char *F_listfile; +extern char *F_symfile; +extern FILE *FI_listfile; +extern FILE *FI_temp; +extern unsigned char Fisclear; +extern unsigned long Plab, Pflags; +extern char Inclevel; +extern char ListMode; +extern unsigned long Processor; + +/*extern unsigned int _fmode;*/ +extern unsigned long CheckSum; + +/* main.c */ +/*extern unsigned char Listing;*/ +void findext(char *str); +int asmerr(int err, bool abort, char *sText); +char *sftos(long val, int flags); +void rmnode(void **base, int bytes); +void addhashtable(MNEMONIC *mne); +void pushinclude(char *str); +char *permalloc(int bytes); +char *zmalloc(int bytes); +char *ckmalloc(int bytes); +char *strlower(char *str); + +/* symbols.c */ +void setspecial(int value, int flags); +SYMBOL *allocsymbol(void); +SYMBOL *findsymbol(char *str, int len); +SYMBOL *CreateSymbol( char *str, int len ); +void freesymbollist(SYMBOL *sym); +void programlabel(void); + +/* ops.c */ +extern unsigned char Gen[]; +extern int Glen; +void v_set(char *str, MNEMONIC *); +void v_mexit(char *str, MNEMONIC *); +void closegenerate(void); + +void v_list(char *, MNEMONIC *); +void v_include(char *, MNEMONIC *); +void v_seg(char *, MNEMONIC *); +void v_dc(char *, MNEMONIC *); +void v_ds(char *, MNEMONIC *); +void v_org(char *, MNEMONIC *); +void v_rorg(char *, MNEMONIC *); +void v_rend(char *, MNEMONIC *); +void v_align(char *, MNEMONIC *); +void v_subroutine(char *, MNEMONIC *); +void v_equ(char *, MNEMONIC *); +void v_eqm(char *, MNEMONIC *); +void v_set(char *, MNEMONIC *); +void v_macro(char *, MNEMONIC *); +void v_endm(char *, MNEMONIC *); +void v_mexit(char *, MNEMONIC *); +void v_ifconst(char *, MNEMONIC *); +void v_ifnconst(char *, MNEMONIC *); +void v_if(char *, MNEMONIC *); +void v_else(char *, MNEMONIC *); +void v_endif(char *, MNEMONIC *); +void v_repeat(char *, MNEMONIC *); +void v_repend(char *, MNEMONIC *); +void v_err(char *, MNEMONIC *); +void v_hex(char *, MNEMONIC *); +void v_trace(char *, MNEMONIC *); +void v_end(char *, MNEMONIC *); +void v_echo(char *, MNEMONIC *); +void v_processor(char *, MNEMONIC *); +void v_incbin(char *, MNEMONIC *); +void v_incdir(char *, MNEMONIC *); +void v_execmac(char *str, MACRO *mac); +void v_mnemonic(char *str, MNEMONIC *mne); + +FILE *pfopen(const char *, const char *); + + +/* exp.c */ +SYMBOL *eval(char *str, int wantmode); + + + + + +/* end of asm.h */ diff --git a/src/copyright.txt b/src/copyright.txt new file mode 100644 index 00000000..afc7fc16 --- /dev/null +++ b/src/copyright.txt @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. \ No newline at end of file diff --git a/src/exp.c b/src/exp.c new file mode 100644 index 00000000..7811da35 --- /dev/null +++ b/src/exp.c @@ -0,0 +1,904 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* +* EXP.C +* +* (c)Copyright 1988, Matthew Dillon, All Rights Reserved. +* Modifications Copyright 1995 by Olaf Seibert. All Rights Reserved. +* +* Handle expression evaluation and addressing mode decode. +* +* NOTE! If you use the string field in an expression you must clear +* the SYM_MACRO and SYM_STRING bits in the flags before calling +* FreeSymbolList()! +*/ + +#include "asm.h" + +#define UNION 0 + +#if UNION /* warning: ANSI disallows cast to union type */ +typedef void (unop)(long v1, int f1); +typedef void (binop)(long v1, long v2, int f1, int f2); + +union unibin { + unop *unary; + binop *binary; +}; + +typedef union unibin opfunc_t; +#define _unary .unary +#define _binary .binary +#else /* warning: Calling functions without prototype */ + +typedef void (*opfunc_t)(); +#define _unary +#define _binary + +#endif + +void stackarg(long val, int flags, char *ptr1); + +void doop(opfunc_t, int pri); +void evaltop(void); +void op_mult(long v1, long v2, int f1, int f2), +op_div(long v1, long v2, int f1, int f2), +op_mod(long v1, long v2, int f1, int f2), +op_add(long v1, long v2, int f1, int f2), +op_sub(long v1, long v2, int f1, int f2), +op_shiftleft(long v1, long v2, int f1, int f2), +op_shiftright(long v1, long v2, int f1, int f2), +op_greater(long v1, long v2, int f1, int f2), +op_greatereq(long v1, long v2, int f1, int f2), +op_smaller(long v1, long v2, int f1, int f2), +op_smallereq(long v1, long v2, int f1, int f2), +op_eqeq(long v1, long v2, int f1, int f2), +op_noteq(long v1, long v2, int f1, int f2), +op_andand(long v1, long v2, int f1, int f2), +op_oror(long v1, long v2, int f1, int f2), +op_xor(long v1, long v2, int f1, int f2), +op_and(long v1, long v2, int f1, int f2), +op_or(long v1, long v2, int f1, int f2), +op_question(long v1, long v2, int f1, int f2); + +void op_takelsb(long v1, int f1), +op_takemsb(long v1, int f1), +op_negate(long v1, int f1), +op_invert(long v1, int f1), +op_not(long v1, int f1); + + +char *pushsymbol(char *str); +char *pushstr(char *str); +char *pushbin(char *str); +char *pushoct(char *str); +char *pushdec(char *str); +char *pushhex(char *str); +char *pushchar(char *str); + +int alphanum(int c); + +/* +* evaluate an expression. Figure out the addressing mode: +* +* implied +* #val immediate +* val zero page or absolute +* val,x zero,x or absolute,x +* val,y zero,y or absolute,y +* (val) indirect +* (val,x) zero indirect x +* (val),y zero indirect y +* +* exp, exp,.. LIST of expressions +* +* an absolute may be returned as zero page +* a relative may be returned as zero page or absolute +* +* unary: - ~ ! < > +* binary: (^)(* / %)(+ -)(>> <<)(& |)(`)(&& ||)(== != < > <= >=) +* +* values: symbol, octal, decimal, $hex, %binary, 'c "str" +* +*/ + +#define MAXOPS 32 +#define MAXARGS 64 + +unsigned char Argflags[MAXARGS]; +long Argstack[MAXARGS]; +char *Argstring[MAXARGS]; +int Oppri[MAXOPS]; +opfunc_t Opdis[MAXOPS]; + +int Argi, Opi, Lastwasop; +int Argibase, Opibase; + +SYMBOL *eval(char *str, int wantmode) +{ + SYMBOL *base, *cur; + int oldargibase = Argibase; + int oldopibase = Opibase; + int scr; + + char *pLine = str; + + Argibase = Argi; + Opibase = Opi; + Lastwasop = 1; + base = cur = allocsymbol(); + + + while (*str) + { + if (Xdebug) + printf("char '%c'\n", *str); + + switch(*str) + { + case ' ': + case '\n': + ++str; + break; + + case '~': + if (Lastwasop) + doop((opfunc_t)op_invert, 128); + else + asmerr( ERROR_SYNTAX_ERROR, false, pLine ); + ++str; + break; + + case '*': + if (Lastwasop) { + pushsymbol("."); + } else + doop((opfunc_t)op_mult, 20); + ++str; + break; + + case '/': + doop((opfunc_t)op_div, 20); + ++str; + break; + + case '%': + if (Lastwasop) { + str = (char *)pushbin(str+1); + } else { + doop((opfunc_t)op_mod, 20); + ++str; + } + break; + + case '?': /* 10 */ + doop((opfunc_t)op_question, 10); + ++str; + break; + + case '+': /* 19 */ + doop((opfunc_t)op_add, 19); + ++str; + break; + + case '-': /* 19: - (or - unary) */ + if (Lastwasop) { + doop((opfunc_t)op_negate, 128); + } else { + doop((opfunc_t)op_sub, 19); + } + ++str; + break; + + case '>': /* 18: >> << 17: > >= <= < */ + + if (Lastwasop) + { + doop((opfunc_t)op_takemsb, 128); + ++str; + break; + } + + if (str[1] == '>') + { + doop((opfunc_t)op_shiftright, 18); + ++str; + } + + else if (str[1] == '=') + { + doop((opfunc_t)op_greatereq, 17); + ++str; + } + else + { + doop((opfunc_t)op_greater, 17); + } + ++str; + break; + + case '<': + + if (Lastwasop) + { + doop((opfunc_t)op_takelsb, 128); + ++str; + break; + } + + if (str[1] == '<') + { + doop((opfunc_t)op_shiftleft, 18); + ++str; + } + else if (str[1] == '=') + { + doop((opfunc_t)op_smallereq, 17); + ++str; + } + else + { + doop((opfunc_t)op_smaller, 17); + } + ++str; + break; + + case '=': /* 16: == (= same as ==) */ + + if (str[1] == '=') + ++str; + doop((opfunc_t)op_eqeq, 16); + ++str; + break; + + case '!': /* 16: != */ + + if (Lastwasop) + { + doop((opfunc_t)op_not, 128); + } + else + { + doop((opfunc_t)op_noteq, 16); + ++str; + } + ++str; + break; + + case '&': /* 15: & 12: && */ + + if (str[1] == '&') + { + doop((opfunc_t)op_andand, 12); + ++str; + } + else + { + doop((opfunc_t)op_and, 15); + } + ++str; + break; + + case '^': /* 14: ^ */ + + doop((opfunc_t)op_xor, 14); + ++str; + break; + + case '|': /* 13: | 11: || */ + + if (str[1] == '|') + { + doop((opfunc_t)op_oror, 11); + ++str; + } + else + { + doop((opfunc_t)op_or, 13); + } + ++str; + break; + + + case '(': + + if (wantmode) + { + cur->addrmode = AM_INDWORD; + ++str; + break; + } + + /* fall thru OK */ + + case '[': /* eventually an argument */ + + if (Opi == MAXOPS) + puts("too many ops"); + else + Oppri[Opi++] = 0; + ++str; + break; + + case ')': + + if (wantmode) + { + if (cur->addrmode == AM_INDWORD && + str[1] == ',' && (str[2]|0x20) == 'y') + { + cur->addrmode = AM_INDBYTEY; + str += 2; + } + ++str; + break; + } + + /* fall thru OK */ + + case ']': + + while(Opi != Opibase && Oppri[Opi-1]) + evaltop(); + if (Opi != Opibase) + --Opi; + ++str; + if (Argi == Argibase) + { + puts("']' error, no arg on stack"); + break; + } + + if (*str == 'd') + { /* STRING CONVERSION */ + char buf[32]; + ++str; + if (Argflags[Argi-1] == 0) + { + sprintf(buf,"%ld",Argstack[Argi-1]); + Argstring[Argi-1] = strcpy(ckmalloc(strlen(buf)+1),buf); + } + } + break; + + case '#': + + cur->addrmode = AM_IMM8; + ++str; + /* + * No other addressing mode is possible from now on + * so we might as well allow () instead of []. + */ + wantmode = 0; + break; + + case ',': + + while(Opi != Opibase) + evaltop(); + Lastwasop = 1; + scr = str[1]|0x20; /* to lower case */ + + if (cur->addrmode == AM_INDWORD && scr == 'x' && !IsAlphaNum( str[2] )) + { + cur->addrmode = AM_INDBYTEX; + ++str; + } + else if (scr == 'x' && !IsAlphaNum(str[2])) + { + cur->addrmode = AM_0X; + ++str; + } + else if (scr == 'y' && !IsAlphaNum(str[2])) + { + cur->addrmode = AM_0Y; + ++str; + } + else + { + SYMBOL *pNewSymbol = allocsymbol(); + cur->next = pNewSymbol; + --Argi; + if (Argi < Argibase) + asmerr( ERROR_SYNTAX_ERROR, false, pLine ); + if (Argi > Argibase) + asmerr( ERROR_SYNTAX_ERROR, false, pLine ); + cur->value = Argstack[Argi]; + cur->flags = Argflags[Argi]; + + if ((cur->string = (void *)Argstring[Argi]) != NULL) + { + cur->flags |= SYM_STRING; + if (Xdebug) + printf("STRING: %s\n", cur->string); + } + cur = pNewSymbol; + } + ++str; + break; + + case '$': + str = pushhex(str+1); + break; + + case '\'': + str = pushchar(str+1); + break; + + case '\"': + str = pushstr(str+1); + break; + + default: + { + char *dol = str; + while (*dol >= '0' && *dol <= '9') + dol++; + if (*dol == '$') + { + str = pushsymbol(str); + break; + } + } + + if (*str == '0') + str = pushoct(str); + else + { + if (*str > '0' && *str <= '9') + str = pushdec(str); + else + str = pushsymbol(str); + } + break; + } + } + + while(Opi != Opibase) + evaltop(); + + if (Argi != Argibase) + { + --Argi; + cur->value = Argstack[Argi]; + cur->flags = Argflags[Argi]; + if ((cur->string = (void *)Argstring[Argi]) != NULL) + { + cur->flags |= SYM_STRING; + if (Xdebug) + printf("STRING: %s\n", cur->string); + } + if (base->addrmode == 0) + base->addrmode = AM_BYTEADR; + } + + if (Argi != Argibase || Opi != Opibase) + asmerr( ERROR_SYNTAX_ERROR, false, pLine ); + + + Argi = Argibase; + Opi = Opibase; + Argibase = oldargibase; + Opibase = oldopibase; + return base; +} + + +int IsAlphaNum( int c ) +{ + return ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9')); +} + +void evaltop(void) +{ + if (Xdebug) + printf("evaltop @(A,O) %d %d\n", Argi, Opi); + + if (Opi <= Opibase) { + asmerr( ERROR_SYNTAX_ERROR, false, NULL ); + Opi = Opibase; + return; + } + --Opi; + if (Oppri[Opi] == 128) { + if (Argi < Argibase + 1) { + asmerr( ERROR_SYNTAX_ERROR, false, NULL ); + Argi = Argibase; + return; + } + --Argi; + (*Opdis[Opi]_unary)(Argstack[Argi], Argflags[Argi]); + } + else + { + if (Argi < Argibase + 2) + { + asmerr( ERROR_SYNTAX_ERROR, false, NULL ); + Argi = Argibase; + return; + } + + Argi -= 2; + (*Opdis[Opi]_binary)(Argstack[Argi], Argstack[Argi+1], + Argflags[Argi], Argflags[Argi+1]); + } +} + +void stackarg(long val, int flags, char *ptr1) +{ + char *str = NULL; + + if (Xdebug) + printf("stackarg %ld (@%d)\n", val, Argi); + + Lastwasop = 0; + if (flags & SYM_STRING) + { + unsigned char *ptr = (unsigned char *)ptr1; + char *new; + int len; + val = len = 0; + while (*ptr && *ptr != '\"') + { + val = (val << 8) | *ptr; + ++ptr; + ++len; + } + new = ckmalloc(len + 1); + memcpy(new, ptr1, len); + new[len] = 0; + flags &= ~SYM_STRING; + str = new; + } + Argstack[Argi] = val; + Argstring[Argi] = str; + Argflags[Argi] = flags; + if (++Argi == MAXARGS) { + puts("stackarg: maxargs stacked"); + Argi = Argibase; + } + while (Opi != Opibase && Oppri[Opi-1] == 128) + evaltop(); +} + +void doop(opfunc_t func, int pri) +{ + if (Xdebug) + puts("doop"); + + Lastwasop = 1; + + if (Opi == Opibase || pri == 128) + { + if (Xdebug) + printf("doop @ %d unary\n", Opi); + Opdis[Opi] = func; + Oppri[Opi] = pri; + ++Opi; + return; + } + + while (Opi != Opibase && Oppri[Opi-1] && pri <= Oppri[Opi-1]) + evaltop(); + + if (Xdebug) + printf("doop @ %d\n", Opi); + + Opdis[Opi] = func; + Oppri[Opi] = pri; + ++Opi; + + if (Opi == MAXOPS) + { + puts("doop: too many operators"); + Opi = Opibase; + } + return; +} + +void op_takelsb(long v1, int f1) +{ + stackarg(v1 & 0xFFL, f1, NULL); +} + +void op_takemsb(long v1, int f1) +{ + stackarg((v1 >> 8) & 0xFF, f1, NULL); +} + +void op_negate(long v1, int f1) +{ + stackarg(-v1, f1, NULL); +} + +void op_invert(long v1, int f1) +{ + stackarg(~v1, f1, NULL); +} + +void op_not(long v1, int f1) +{ + stackarg(!v1, f1, NULL); +} + +void op_mult(long v1, long v2, int f1, int f2) +{ + stackarg(v1 * v2, f1|f2, NULL); +} + +void op_div(long v1, long v2, int f1, int f2) +{ + if (f1|f2) { + stackarg(0L, f1|f2, NULL); + return; + } + if (v2 == 0) + { + asmerr( ERROR_DIVISION_BY_0, true, NULL ); + stackarg(0L, 0, NULL); + } + else + { + stackarg(v1 / v2, 0, NULL); + } +} + +void op_mod(long v1, long v2, int f1, int f2) +{ + if (f1|f2) { + stackarg(0L, f1|f2, NULL); + return; + } + if (v2 == 0) + stackarg(v1, 0, NULL); + else + stackarg(v1 % v2, 0, NULL); +} + +void op_question(long v1, long v2, int f1, int f2) +{ + if (f1) + stackarg(0L, f1, NULL); + else + stackarg((long)((v1) ? v2 : 0), ((v1) ? f2 : 0), NULL); +} + +void op_add(long v1, long v2, int f1, int f2) +{ + stackarg(v1 + v2, f1|f2, NULL); +} + +void op_sub(long v1, long v2, int f1, int f2) +{ + stackarg(v1 - v2, f1|f2, NULL); +} + +void op_shiftright(long v1, long v2, int f1, int f2) +{ + if (f1|f2) + stackarg(0L, f1|f2, NULL); + else + stackarg((long)(v1 >> v2), 0, NULL); +} + +void op_shiftleft(long v1, long v2, int f1, int f2) +{ + if (f1|f2) + stackarg(0L, f1|f2, NULL); + else + stackarg((long)(v1 << v2), 0, NULL); +} + +void op_greater(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 > v2), f1|f2, NULL); +} + +void op_greatereq(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 >= v2), f1|f2, NULL); +} + +void op_smaller(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 < v2), f1|f2, NULL); +} + +void op_smallereq(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 <= v2), f1|f2, NULL); +} + +void op_eqeq(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 == v2), f1|f2, NULL); +} + +void op_noteq(long v1, long v2, int f1, int f2) +{ + stackarg((long)(v1 != v2), f1|f2, NULL); +} + +void op_andand(long v1, long v2, int f1, int f2) +{ + if ((!f1 && !v1) || (!f2 && !v2)) { + stackarg(0L, 0, NULL); + return; + } + stackarg(1L, f1|f2, NULL); +} + +void op_oror(long v1, long v2, int f1, int f2) +{ + if ((!f1 && v1) || (!f2 && v2)) { + stackarg(1L, 0, NULL); + return; + } + stackarg(0L, f1|f2, NULL); +} + +void op_xor(long v1, long v2, int f1, int f2) +{ + stackarg(v1^v2, f1|f2, NULL); +} + +void op_and(long v1, long v2, int f1, int f2) +{ + stackarg(v1&v2, f1|f2, NULL); +} + +void op_or(long v1, long v2, int f1, int f2) +{ + stackarg(v1|v2, f1|f2, NULL); +} + +char *pushchar(char *str) +{ + if (*str) { + stackarg((long)*str, 0, NULL); + ++str; + } else { + stackarg((long)' ', 0, NULL); + } + return str; +} + +char *pushhex(char *str) +{ + long val = 0; + for (;; ++str) { + if (*str >= '0' && *str <= '9') { + val = (val << 4) + (*str - '0'); + continue; + } + if ((*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) { + val = (val << 4) + ((*str&0x1F) + 9); + continue; + } + break; + } + stackarg(val, 0, NULL); + return str; +} + +char *pushoct(char *str) +{ + long val = 0; + while (*str >= '0' && *str <= '7') { + val = (val << 3) + (*str - '0'); + ++str; + } + stackarg(val, 0, NULL); + return str; +} + +char *pushdec(char *str) +{ + long val = 0; + while (*str >= '0' && *str <= '9') { + val = (val * 10) + (*str - '0'); + ++str; + } + stackarg(val, 0, NULL); + return str; +} + +char *pushbin(char *str) +{ + long val = 0; + while (*str == '0' || *str == '1') { + val = (val << 1) | (*str - '0'); + ++str; + } + stackarg(val, 0, NULL); + return str; +} + +char *pushstr(char *str) +{ + stackarg(0, SYM_STRING, str); + while (*str && *str != '\"') + ++str; + if (*str == '\"') + ++str; + return str; +} + +char *pushsymbol(char *str) +{ + SYMBOL *sym; + char *ptr; + unsigned char macro = 0; + + for (ptr = str; + *ptr == '_' || + *ptr == '.' || + (*ptr >= 'a' && *ptr <= 'z') || + (*ptr >= 'A' && *ptr <= 'Z') || + (*ptr >= '0' && *ptr <= '9'); + ++ptr + ); + if (ptr == str) { + asmerr( ERROR_ILLEGAL_CHARACTER, false, str ); + printf("char = '%c' %d (-1: %d)\n", *str, *str, *(str-1)); + if (F_listfile) + fprintf(FI_listfile, "char = '%c' code %d\n", *str, *str); + return str+1; + } + + if (*ptr == '$') + ptr++; + + if ((sym = findsymbol(str, ptr - str)) != NULL) + { + if (sym->flags & SYM_UNKNOWN) + ++Redo_eval; + + if (sym->flags & SYM_MACRO) + { + macro = 1; + sym = eval(sym->string, 0); + } + + if (sym->flags & SYM_STRING) + stackarg(0, SYM_STRING, sym->string); + + else + stackarg(sym->value, sym->flags & SYM_UNKNOWN, NULL); + + sym->flags |= SYM_REF|SYM_MASREF; + + if (macro) + FreeSymbolList(sym); + } + else + { + stackarg(0L, SYM_UNKNOWN, NULL); + sym = CreateSymbol( str, ptr - str ); + sym->flags = SYM_REF|SYM_MASREF|SYM_UNKNOWN; + ++Redo_eval; + } + return ptr; +} + + diff --git a/src/ftohex.c b/src/ftohex.c new file mode 100644 index 00000000..64cce1f6 --- /dev/null +++ b/src/ftohex.c @@ -0,0 +1,173 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* + * FTOHEX.C + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + * + * FTOHEX format infile [outfile] + * + * format: format used when assembling (asm705/asm65) + * 1,2,3 -generate straight hex file + * + * compilable on an ibm-pc or Amiga _fmode is for Lattice C on the ibm, + * is IGNORED by Aztec C on the Amiga. Note that INT and CHAR are not + * used as ibm's lattice C uses 16 bit ints and unsigned chars. Change + * as needed. No guarentees for the IBMPC version. + * FTOHEX format infile [outfile] + */ + +#include +#include + + +#define PERLINE 16 + +void exiterr(char *str); +void convert(int format, FILE *in, FILE *out); +unsigned int getwlh(FILE *in); +void puth(unsigned char c, FILE *out); + +unsigned int _fmode = 0; + +int +main(int ac, char **av) +{ + int format; + FILE *infile; + FILE *outfile; + + _fmode = 0x8000; + if (ac < 3) { + puts("FTOHEX format infile [outfile]"); + puts("format 1,2, or 3. 3=raw"); + puts("(C)Copyright 1987 by Matthew Dillon, All Rights Reserved"); + exit(1); + } + format = atoi(av[1]); + if (format < 1 || format > 3) + exiterr("specify infile format 1, 2, or 3"); + infile = fopen(av[2], "r"); + if (infile == NULL) + exiterr("unable to open input file"); + outfile = (av[3]) ? fopen(av[3], "w") : stdout; + if (outfile == NULL) + exiterr("unable to open output file"); + convert(format, infile, outfile); + fclose(infile); + fclose(outfile); + + return 0; +} + +void +exiterr(char *str) +{ + fputs(str, stderr); + fputs("\n", stderr); + exit(1); +} + +/* + * Formats: + * + * 1: origin (word:lsb,msb) + data + * 2: origin (word:lsb,msb) + length (word:lsb,msb) + data (repeat) + * 3: data + * + * Hex output: + * + * :lloooo00(ll bytes hex code)cc ll=# of bytes + * oooo=origin + * cc=invert of checksum all codes + */ + +void +convert(int format, FILE *in, FILE *out) +{ + unsigned int org = 0; + unsigned int idx; + long len; + unsigned char buf[256]; + + if (format < 3) + org = getwlh(in); + if (format == 2) { + len = getwlh(in); + } else { + long begin = ftell(in); + fseek(in, 0, SEEK_END); + len = ftell(in) - begin; + fseek(in, begin, 0); + } + for (;;) { + while (len > 0) { + register unsigned char chk; + register int i; + + idx = (len > PERLINE) ? PERLINE : len; + fread(buf, idx, 1, in); + putc(':', out); + puth(idx, out); + puth(org >> 8, out); + puth(org & 0xFF, out); + putc('0', out); + putc('0', out); + chk = idx + (org >> 8) + (org & 0xFF); + for (i = 0; i < idx; ++i) { + chk += buf[i]; + puth(buf[i], out); + } + puth((unsigned char)-chk, out); + putc('\r', out); + putc('\n', out); + len -= idx; + org += idx; + } + if (format == 2) { + org = getwlh(in); + if (feof(in)) + break; + len = getwlh(in); + } else { + break; + } + } + fprintf(out, ":00000001FF\r\n"); +} + +unsigned int getwlh(FILE *in) +{ + unsigned int result; + + result = getc(in); + result += getc(in) << 8; + return result; +} + +void +puth(unsigned char c, FILE *out) +{ + static char dig[] = { "0123456789ABCDEF" }; + putc(dig[c>>4], out); + putc(dig[c&15], out); +} + diff --git a/src/globals.c b/src/globals.c new file mode 100644 index 00000000..cf8f7820 --- /dev/null +++ b/src/globals.c @@ -0,0 +1,123 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* + * GLOBALS.C + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + * Modifications Copyright 1995 by Olaf Seibert. All Rights Reserved. + * + */ + +#include "asm.h" + +SYMBOL *SHash[SHASHSIZE]; /* symbol hash table */ + + +MNEMONIC *MHash[MHASHSIZE]; /* mnemonic hash table */ +INCFILE *pIncfile; /* include file stack */ +REPLOOP *Reploop; /* repeat loop stack */ +SEGMENT *Seglist; /* segment list */ +SEGMENT *Csegment; /* current segment */ +IFSTACK *Ifstack; /* IF/ELSE/ENDIF stack */ +char *Av[256]; /* up to 256 arguments */ +char Avbuf[512]; +unsigned char MsbOrder = 1; +int Mnext; +char Inclevel; +unsigned int Mlevel; +unsigned long Localindex; /* to generate local variables */ +unsigned long Lastlocalindex; + +unsigned long Localdollarindex; +unsigned long Lastlocaldollarindex; + +unsigned long Processor = 0; +bool bTrace = false; +bool Xdebug; + +unsigned char Outputformat; + +unsigned long Redo_why = 0; +int Redo_eval = 0; /* infinite loop detection only */ +int Redo = 0; + + +unsigned long Redo_if = 0; + +char ListMode = 1; +unsigned long CheckSum; /* output data checksum */ + +int F_format = FORMAT_DEFAULT; + +unsigned char F_verbose; +char *F_outfile = "a.out"; +char *F_listfile; +char *F_symfile; +FILE *FI_listfile; +FILE *FI_temp; +unsigned char Fisclear; +unsigned long Plab, Pflags; + +/*unsigned int Adrbytes[] = { 1, 2, 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 3, 1, 1, 2, 3 };*/ +unsigned int Cvt[] = { 0, 2, 0, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0 }; +unsigned int Opsize[] = { 0, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 0, 0, 1, 1 }; + +MNEMONIC Ops[] = { + { NULL, v_list , "list", 0, 0, }, + { NULL, v_include , "include", 0, 0, }, + { NULL, v_seg , "seg", 0, 0, }, + { NULL, v_hex , "hex", 0, 0, }, + { NULL, v_err , "err", 0, 0, }, + { NULL, v_dc , "dc", 0, 0, }, + { NULL, v_dc , "byte", 0, 0, }, + { NULL, v_dc , "word", 0, 0, }, + { NULL, v_dc , "long", 0, 0, }, + { NULL, v_ds , "ds", 0, 0, }, + { NULL, v_dc , "dv", 0, 0, }, + { NULL, v_end , "end", 0, 0, }, + { NULL, v_trace , "trace", 0, 0, }, + { NULL, v_org , "org", 0, 0, }, + { NULL, v_rorg , "rorg", 0, 0, }, + { NULL, v_rend , "rend", 0, 0, }, + { NULL, v_align , "align", 0, 0, }, + { NULL, v_subroutine, "subroutine", 0, 0, }, + { NULL, v_equ , "equ", 0, 0, }, + { NULL, v_equ , "=", 0, 0, }, + { NULL, v_eqm , "eqm", 0, 0, }, + { NULL, v_set , "set", 0, 0, }, + { NULL, v_macro , "mac", MF_IF, 0, }, + { NULL, v_endm , "endm", MF_ENDM,0, }, + { NULL, v_mexit , "mexit", 0, 0, }, + { NULL, v_ifconst , "ifconst", MF_IF, 0, }, + { NULL, v_ifnconst, "ifnconst", MF_IF, 0, }, + { NULL, v_if , "if", MF_IF, 0, }, + { NULL, v_else , "else", MF_IF, 0, }, + { NULL, v_endif , "endif", MF_IF, 0, }, + { NULL, v_endif , "eif", MF_IF, 0, }, + { NULL, v_repeat , "repeat", MF_IF, 0, }, + { NULL, v_repend , "repend", MF_IF, 0, }, + { NULL, v_echo , "echo", 0, 0, }, + { NULL, v_processor,"processor", 0, 0, }, + { NULL, v_incbin, "incbin", 0, 0, }, + { NULL, v_incdir, "incdir", 0, 0, }, + { NULL, } +}; + diff --git a/src/main.c b/src/main.c new file mode 100644 index 00000000..c799b009 --- /dev/null +++ b/src/main.c @@ -0,0 +1,1476 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* +* MAIN.C +* DASM sourcefile +* NOTE: must handle mnemonic extensions and expression decode/compare. +*/ + + +#include "asm.h" + + +#define MAXLINE 1024 +#define ISEGNAME "INITIAL CODE SEGMENT" + +char *cleanup(char *buf, bool bDisable); + +MNEMONIC *parse(char *buf); +void panic(char *str); +MNEMONIC *findmne(char *str); +void clearsegs(void); +void clearrefs(void); + +static unsigned int hash1(char *str); +static void outlistfile(char *); + + + +/* Table encapsulates errors, descriptions, and fatality flags. */ + +ERROR_DEFINITION sErrorDef[] = { + + /* Error #, STOPEND, Description */ + + { ERROR_NONE, true, "OK" }, + { ERROR_COMMAND_LINE, true, "Check command-line format." }, + { ERROR_FILE_ERROR, true, "Unable to open file." }, + { ERROR_NOT_RESOLVABLE, true, "Source is not resolvable." }, + { ERROR_TOO_MANY_PASSES, true, "Too many passes (%s)." }, + { ERROR_SYNTAX_ERROR, true, "Syntax Error '%s'." }, + { ERROR_EXPRESSION_TABLE_OVERFLOW, true, "Expression table overflow." }, + { ERROR_UNBALANCED_BRACES, true, "Unbalanced Braces []." }, + { ERROR_DIVISION_BY_0, true, "Division by zero." }, + { ERROR_UNKNOWN_MNEMONIC, true, "Unknown Mnemonic '%s'." }, + { ERROR_ILLEGAL_ADDRESSING_MODE, false, "Illegal Addressing mode '%s'." }, + { ERROR_ILLEGAL_FORCED_ADDRESSING_MODE, true, "Illegal forced Addressing mode on '%s'." }, + { ERROR_NOT_ENOUGH_ARGUMENTS_PASSED_TO_MACRO, true, "Not enough args passed to Macro." }, + { ERROR_PREMATURE_EOF, false, "Premature EOF." }, + { ERROR_ILLEGAL_CHARACTER, true, "Illegal character '%s'." }, + { ERROR_BRANCH_OUT_OF_RANGE, true, "Branch out of range (%s bytes)." }, + { ERROR_ERR_PSEUDO_OP_ENCOUNTERED, true, "ERR pseudo-op encountered." }, + { ERROR_ORIGIN_REVERSE_INDEXED, false, "Origin Reverse-indexed." }, + { ERROR_EQU_VALUE_MISMATCH, false, "EQU: Value mismatch." }, + { ERROR_ADDRESS_MUST_BE_LT_100, true, "Value in '%s' must be <$100." }, + { ERROR_ILLEGAL_BIT_SPECIFICATION, true, "Illegal bit specification." }, + { ERROR_NOT_ENOUGH_ARGS, true, "Not enough arguments." }, + { ERROR_LABEL_MISMATCH, true, "Label mismatch...\n --> %s" }, + { ERROR_VALUE_UNDEFINED, true, "Value Undefined." }, + { ERROR_PROCESSOR_NOT_SUPPORTED, true, "Processor '%s' not supported." }, + { ERROR_REPEAT_NEGATIVE, false, "REPEAT parameter < 0 (ignored)." }, + { ERROR_BADERROR, true, "Bad error value (internal error)." }, + { ERROR_ONLY_ONE_PROCESSOR_SUPPORTED, true, "Only one processor type may be selected." }, + { ERROR_BAD_FORMAT, true, "Bad output format specified." }, + { ERROR_VALUE_MUST_BE_1_OR_4, true, "Value in '%s' must be 1 or 4." }, + { ERROR_VALUE_MUST_BE_LT_10, true, "Value in '%s' must be <$10." }, + { ERROR_VALUE_MUST_BE_LT_8, true, "Value in '%s' must be <$8." }, + { ERROR_VALUE_MUST_BE_LT_F, true, "Value in '%s' must be <$f." }, + { ERROR_VALUE_MUST_BE_LT_10000, true, "Value in '%s' must be <$10000." }, + { ERROR_ILLEGAL_OPERAND_COMBINATION, true, "Illegal combination of operands '%s'" }, + NULL +}; + +#define MAX_ERROR (( sizeof( sErrorDef ) / sizeof( ERROR_DEFINITION ))) + +bool bStopAtEnd = false; + + +char *Extstr; +/*unsigned char Listing = 1;*/ +int pass; + +unsigned char F_ListAllPasses = 0; + + + +const char name[] = "DASM V2.20.10, Macro Assembler (C)1988-2004"; + + + +int CountUnresolvedSymbols() +{ + SYMBOL *sym; + int nUnresolved = 0; + int i; + + /* Pre-count unresolved symbols */ + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + if ( sym->flags & SYM_UNKNOWN ) + nUnresolved++; + + return nUnresolved; +} + + +int ShowUnresolvedSymbols() +{ + SYMBOL *sym; + int i; + + int nUnresolved = CountUnresolvedSymbols(); + if ( nUnresolved ) + { + printf( "--- Unresolved Symbol List\n" ); + + /* Display unresolved symbols */ + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + if ( sym->flags & SYM_UNKNOWN ) + printf( "%-24s %s\n", sym->name, sftos( sym->value, sym->flags ) ); + + printf( "--- %d Unresolved Symbol%c\n\n", nUnresolved, ( nUnresolved == 1 ) ? ' ' : 's' ); + } + + return nUnresolved; +} + + +int CompareAlpha( const void *arg1, const void *arg2 ) +{ + /* Simple alphabetic ordering comparison function for quicksort */ + + SYMBOL **sym1, **sym2; + int nSym1Size, nSym2Size; + char *pSym1LC, *pSym2LC; + char *pSrc, *pDest; + int nCompare; + + sym1 = (SYMBOL **) arg1; + sym2 = (SYMBOL **) arg2; + + nSym1Size = strlen( (*sym1)->name ) + 1; + nSym2Size = strlen( (*sym2)->name ) + 1; + + + + /* Primitive manual to lowercase conversion */ + + pSym1LC = ckmalloc( nSym1Size ); + pDest = pSym1LC; + pSrc = (*sym1)->name; + while ( *pSrc ) + { + if ( *pSrc >= 'A' && *pSrc <= 'Z' ) + *pDest = *pSrc - 'A' + 'a'; + else + *pDest = *pSrc; + + *pDest++; + *pSrc++; + } + *pDest = 0; /* terminator */ + + /* Primitive manual to lowercase conversion */ + + pSym2LC = ckmalloc( nSym2Size ); + pDest = pSym2LC; + pSrc = (*sym2)->name; + while ( *pSrc ) + { + if ( *pSrc >= 'A' && *pSrc <= 'Z' ) + *pDest = *pSrc - 'A' + 'a'; + else + *pDest = *pSrc; + + *pDest++; + *pSrc++; + } + *pDest = 0; /* terminator */ + + nCompare = strcmp( pSym1LC, pSym2LC ); + + free( pSym2LC ); + free( pSym1LC ); + + return nCompare; +} + +int CompareAddress( const void *arg1, const void *arg2 ) +{ + /* Simple numeric ordering comparison function for quicksort */ + + SYMBOL **sym1, **sym2; + + sym1 = (SYMBOL **) arg1; + sym2 = (SYMBOL **) arg2; + + return (*sym1)->value - (*sym2)->value; +} + + +void ShowSymbols( FILE *file, bool bTableSort ) +{ + /* Display sorted (!) symbol table - if it runs out of memory, table will be displayed unsorted */ + + SYMBOL **symArray; + SYMBOL *sym; + int i; + int nSymbols = 0; + + fprintf( file, "--- Symbol List"); + + /* Sort the symbol list either via name, or by value */ + + /* First count the number of symbols */ + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + nSymbols++; + + /* Malloc an array of pointers to data */ + + symArray = (SYMBOL **)ckmalloc( sizeof( SYMBOL * ) * nSymbols ); + if ( !symArray ) + { + fprintf( file, " (unsorted - not enough memory to sort!)\n" ); + + /* Display complete symbol table */ + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + fprintf( file, "%-24s %s\n", sym->name, sftos( sym->value, sym->flags ) ); + } + else + { + /* Copy the element pointers into the symbol array */ + + int nPtr = 0; + + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + symArray[ nPtr++ ] = sym; + + if ( bTableSort ) + { + fprintf( file, " (sorted by address)\n" ); + qsort( symArray, nPtr, sizeof( SYMBOL * ), CompareAddress ); /* Sort via address */ + } + else + { + fprintf( file, " (sorted by symbol)\n" ); + qsort( symArray, nPtr, sizeof( SYMBOL * ), CompareAlpha ); /* Sort via name */ + } + + + /* now display sorted list */ + + for ( i = 0; i < nPtr; i++ ) + { + fprintf( file, "%-24s %-12s", symArray[ i ]->name, + sftos( symArray[ i ]->value, symArray[ i ]->flags ) ); + if ( symArray[ i ]->flags & SYM_STRING ) + fprintf( file, " \"%s\"", symArray[ i ]->string ); /* If a string, display actual string */ + fprintf( file, "\n" ); + } + + free( symArray ); + } + + fputs( "--- End of Symbol List.\n", file ); + +} + + + +void ShowSegments() +{ + SEGMENT *seg; + char *bss; + char *sFormat = "%-24s %-3s %-8s %-8s %-8s %-8s\n\0"; + + + + printf("\n----------------------------------------------------------------------\n"); + printf( sFormat, "SEGMENT NAME", "", "INIT PC", "INIT RPC", "FINAL PC", "FINAL RPC" ); + + for (seg = Seglist; seg; seg = seg->next) + { + bss = (seg->flags & SF_BSS) ? "[u]" : " "; + + printf( sFormat, seg->name, bss, + sftos(seg->initorg, seg->initflags), sftos(seg->initrorg, seg->initrflags), + sftos(seg->org, seg->flags), sftos(seg->rorg, seg->rflags) ); + } + puts("----------------------------------------------------------------------"); + + printf( "%d references to unknown symbols.\n", Redo_eval ); + printf( "%d events requiring another assembler pass.\n", Redo ); + + if ( Redo_why ) + { + if ( Redo_why & REASON_MNEMONIC_NOT_RESOLVED ) + printf( " - Expression in mnemonic not resolved.\n" ); + + if ( Redo_why & REASON_OBSCURE ) + printf( " - Obscure reason - to be documented :)\n" ); + + if ( Redo_why & REASON_DC_NOT_RESOVED ) + printf( " - Expression in a DC not resolved.\n" ); + + if ( Redo_why & REASON_DV_NOT_RESOLVED_PROBABLY ) + printf( " - Expression in a DV not resolved (probably in DV's EQM symbol).\n" ); + + if ( Redo_why & REASON_DV_NOT_RESOLVED_COULD ) + printf( " - Expression in a DV not resolved (could be in DV's EQM symbol).\n" ); + + if ( Redo_why & REASON_DS_NOT_RESOLVED ) + printf( " - Expression in a DS not resolved.\n" ); + + if ( Redo_why & REASON_ALIGN_NOT_RESOLVED ) + printf( " - Expression in an ALIGN not resolved.\n" ); + + if ( Redo_why & REASON_ALIGN_RELOCATABLE_ORIGIN_NOT_KNOWN ) + printf( " - ALIGN: Relocatable origin not known (if in RORG at the time).\n" ); + + if ( Redo_why & REASON_ALIGN_NORMAL_ORIGIN_NOT_KNOWN ) + printf( " - ALIGN: Normal origin not known (if in ORG at the time).\n" ); + + if ( Redo_why & REASON_EQU_NOT_RESOLVED ) + printf( " - EQU: Expression not resolved.\n" ); + + if ( Redo_why & REASON_EQU_VALUE_MISMATCH ) + printf( " - EQU: Value mismatch from previous pass (phase error).\n" ); + + if ( Redo_why & REASON_IF_NOT_RESOLVED ) + printf( " - IF: Expression not resolved.\n" ); + + if ( Redo_why & REASON_REPEAT_NOT_RESOLVED ) + printf( " - REPEAT: Expression not resolved.\n" ); + + if ( Redo_why & REASON_FORWARD_REFERENCE ) + printf( " - Label defined after it has been referenced (forward reference).\n" ); + + if ( Redo_why & REASON_PHASE_ERROR ) + printf( " - Label value is different from that of the previous pass (phase error).\n" ); + } + + printf( "\n" ); + +} + + + +void DumpSymbolTable( bool bTableSort ) +{ + if (F_symfile) + { + FILE *fi = fopen(F_symfile, "w"); + if (fi) + { + ShowSymbols( fi, bTableSort ); + fclose(fi); + } + else + { + printf("Warning: Unable to open Symbol Dump file '%s'\n", F_symfile); + } + } + +} + + +int MainShadow(int ac, char **av, bool *pbTableSort ) +{ + + + + int nError = ERROR_NONE; + bool bDoAllPasses = false; + int nMaxPasses = 10; + + char buf[MAXLINE]; + int i; + MNEMONIC *mne; + + int oldredo = -1; + unsigned long oldwhy = 0; + int oldeval = 0; + + addhashtable(Ops); + pass = 1; + + if (ac < 2) + { + +fail: + puts("redistributable for non-profit only"); + puts(""); + puts("DASM sourcefile [options]"); + puts(" -f# output format"); + puts(" -oname output file"); + puts(" -lname list file"); + puts(" -Lname list file, containing all passes"); + puts(" -sname symbol dump"); + puts(" -v# verboseness"); + puts(" -t# Symbol Table sorting preference (#1 = by address. default #0 = alphabetic)" ); + puts(" -Dname=exp define label"); + puts(" -Mname=exp define label as in EQM"); + puts(" -Idir search directory for include and incbin"); + puts(" -p# max number of passes"); + puts(" -P# max number of passes, with less checks"); + + return ERROR_COMMAND_LINE; + } + + puts(name); + + for (i = 2; i < ac; ++i) + { + if ( ( av[i][0] == '-' ) || ( av[i][0] == '/' ) ) + { + char *str = av[i]+2; + switch(av[i][1]) + { + + case 'T': + *pbTableSort = ( atoi( str ) != 0 ); + break; + + case 'd': + Xdebug = atoi(str) != 0; + printf( "Debug trace %s\n", Xdebug ? "ON" : "OFF" ); + break; + + case 'M': + case 'D': + while (*str && *str != '=') + ++str; + if (*str == '=') + { + *str = 0; + ++str; + } + else + { + str = "0"; + } + Av[0] = av[i]+2; + + if (av[i][1] == 'M') + v_eqm(str, NULL); + else + v_set(str, NULL); + break; + + case 'f': /* F_format */ + F_format = atoi(str); + if (F_format < FORMAT_DEFAULT || F_format >= FORMAT_MAX ) + panic("Illegal format specification"); + break; + + case 'o': /* F_outfile */ + F_outfile = str; +nofile: + if (*str == 0) + panic("-o Switch requires file name."); + break; + + case 'L': + F_ListAllPasses = 1; + /* fall through to 'l' */ + + case 'l': /* F_listfile */ + F_listfile = str; + goto nofile; + + case 'P': /* F_Passes */ + bDoAllPasses = true; + + /* fall through to 'p' */ + case 'p': /* F_passes */ + nMaxPasses = atoi(str); + break; + + case 's': /* F_symfile */ + F_symfile = str; + goto nofile; + case 'v': /* F_verbose */ + F_verbose = atoi(str); + break; + + case 't': /* F_temppath */ + break; + + case 'I': + v_incdir(str, NULL); + break; + + default: + goto fail; + } + continue; + } + goto fail; + } + + /* INITIAL SEGMENT */ + + { + SEGMENT *seg = (SEGMENT *)permalloc(sizeof(SEGMENT)); + seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME); + seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN; + Csegment = Seglist = seg; + } + /* TOP LEVEL IF */ + { + IFSTACK *ifs = (IFSTACK *)zmalloc(sizeof(IFSTACK)); + ifs->file = NULL; + ifs->flags = IFF_BASE; + ifs->acctrue = 1; + ifs->xtrue = 1; + Ifstack = ifs; + } + + +nextpass: + + + if ( F_verbose ) + { + puts(""); + printf("START OF PASS: %d\n", pass); + } + + Localindex = Lastlocalindex = 0; + + Localdollarindex = Lastlocaldollarindex = 0; + + /*_fmode = 0x8000;*/ + FI_temp = fopen(F_outfile, "wb"); + /*_fmode = 0;*/ + Fisclear = 1; + CheckSum = 0; + if (FI_temp == NULL) { + printf("Warning: Unable to [re]open '%s'\n", F_outfile); + return ERROR_FILE_ERROR; + } + if (F_listfile) { + + FI_listfile = fopen(F_listfile, + F_ListAllPasses && (pass > 1)? "a" : "w"); + + if (FI_listfile == NULL) { + printf("Warning: Unable to [re]open '%s'\n", F_listfile); + return ERROR_FILE_ERROR; + } + } + pushinclude(av[1]); + + while ( pIncfile ) + { + for (;;) { + char *comment; + if ( pIncfile->flags & INF_MACRO) { + if ( pIncfile->strlist == NULL) { + Av[0] = ""; + v_mexit(NULL, NULL); + continue; + } + strcpy(buf, pIncfile->strlist->buf); + pIncfile->strlist = pIncfile->strlist->next; + } + else + { + if (fgets(buf, MAXLINE, pIncfile->fi) == NULL) + break; + } + + if (Xdebug) + printf("%08lx %s\n", (unsigned long) pIncfile, buf); + + comment = cleanup(buf, false); + ++pIncfile->lineno; + mne = parse(buf); + + if (Av[1][0]) + { + if (mne) + { + if ((mne->flags & MF_IF) || (Ifstack->xtrue && Ifstack->acctrue)) + (*mne->vect)(Av[2], mne); + } + else + { + if (Ifstack->xtrue && Ifstack->acctrue) + asmerr( ERROR_UNKNOWN_MNEMONIC, false, Av[1] ); + } + + } + else + { + if (Ifstack->xtrue && Ifstack->acctrue) + programlabel(); + } + + if (F_listfile && ListMode) + outlistfile(comment); + } + + while (Reploop && Reploop->file == pIncfile) + rmnode((void **)&Reploop, sizeof(REPLOOP)); + + while (Ifstack->file == pIncfile) + rmnode((void **)&Ifstack, sizeof(IFSTACK)); + + fclose( pIncfile->fi ); + free( pIncfile->name ); + --Inclevel; + rmnode((void **)&pIncfile, sizeof(INCFILE)); + + if ( pIncfile ) + { + /* + if (F_verbose > 1) + printf("back to: %s\n", Incfile->name); + */ + if (F_listfile) + fprintf(FI_listfile, "------- FILE %s\n", pIncfile->name); + } + } + + + + if ( F_verbose >= 1 ) + ShowSegments(); + + if ( F_verbose >= 3 ) + { + if ( !Redo || ( F_verbose == 4 ) ) + ShowSymbols( stdout, *pbTableSort ); + + ShowUnresolvedSymbols(); + } + + closegenerate(); + fclose(FI_temp); + if (FI_listfile) + fclose(FI_listfile); + + if (Redo) + { + if ( !bDoAllPasses ) + if (Redo == oldredo && Redo_why == oldwhy && Redo_eval == oldeval) + { + ShowUnresolvedSymbols(); + return ERROR_NOT_RESOLVABLE; + } + + oldredo = Redo; + oldwhy = Redo_why; + oldeval = Redo_eval; + Redo = 0; + Redo_why = 0; + Redo_eval = 0; + + Redo_if <<= 1; + ++pass; + + if ( bStopAtEnd ) + { + printf("Unrecoverable error(s) in pass, aborting assembly!\n"); + } + else if ( pass > nMaxPasses ) + { + char sBuffer[64]; + sprintf( sBuffer, "%d", pass ); + return asmerr( ERROR_TOO_MANY_PASSES, false, sBuffer ); + + } + else + { + clearrefs(); + clearsegs(); + goto nextpass; + } + } + + printf( "Complete.\n" ); + + return nError; +} + + +int tabit(char *buf1, char *buf2) +{ + char *bp, *ptr; + int j, k; + + bp = buf2; + ptr= buf1; + for (j = 0; *ptr && *ptr != '\n'; ++ptr, ++bp, j = (j+1)&7) { + *bp = *ptr; + if (*ptr == '\t') { + /* optimize out spaces before the tab */ + while (j > 0 && bp[-1] == ' ') { + bp--; + j--; + } + j = 0; + *bp = '\t'; /* recopy the tab */ + } + if (j == 7 && *bp == ' ' && bp[-1] == ' ') { + k = j; + while (k-- >= 0 && *bp == ' ') + --bp; + *++bp = '\t'; + } + } + while (bp != buf2 && (bp[-1] == ' ' || bp[-1] == '\t')) + --bp; + *bp++ = '\n'; + *bp = '\0'; + return (int)(bp - buf2); +} + +static void outlistfile(char *comment) +{ + char xtrue; + char c; + static char buf1[MAXLINE+32]; + static char buf2[MAXLINE+32]; + char *ptr; + char *dot; + int i, j; + + + if ( pIncfile->flags & INF_NOLIST ) + return; + + xtrue = (Ifstack->xtrue && Ifstack->acctrue) ? ' ' : '-'; + c = (Pflags & SF_BSS) ? 'U' : ' '; + ptr = Extstr; + dot = ""; + if (ptr) + dot = "."; + else + ptr = ""; + + sprintf(buf1, "%7ld %c%s", pIncfile->lineno, c, sftos(Plab, Pflags & 7)); + j = strlen(buf1); + for (i = 0; i < Glen && i < 4; ++i, j += 3) + sprintf(buf1+j, "%02x ", Gen[i]); + if (i < Glen && i == 4) + xtrue = '*'; + for (; i < 4; ++i) { + buf1[j] = buf1[j+1] = buf1[j+2] = ' '; + j += 3; + } + sprintf(buf1+j-1, "%c%-10s %s%s%s\t%s\n", + xtrue, Av[0], Av[1], dot, ptr, Av[2]); + if (comment[0]) { /* tab and comment */ + j = strlen(buf1) - 1; + sprintf(buf1+j, "\t;%s", comment); + } + fwrite(buf2, tabit(buf1,buf2), 1, FI_listfile); + Glen = 0; + Extstr = NULL; +} + +char *sftos(long val, int flags) +{ + static char buf[ MAX_SYM_LEN + 14 ]; + static char c; + char *ptr = (c) ? buf : buf + sizeof(buf) / 2; + + memset( buf, 0, sizeof( buf ) ); + + c = 1 - c; + + sprintf(ptr, "%04lx ", val); + + if (flags & SYM_UNKNOWN) + strcat( ptr, "???? "); + else + strcat( ptr, " " ); + + if (flags & SYM_STRING) + strcat( ptr, "str "); + else + strcat( ptr, " " ); + + if (flags & SYM_MACRO) + strcat( ptr, "eqm "); + else + strcat( ptr, " " ); + + + if (flags & (SYM_MASREF|SYM_SET)) + { + strcat( ptr, "(" ); + } + else + strcat( ptr, " " ); + + if (flags & (SYM_MASREF)) + strcat( ptr, "R" ); + else + strcat( ptr, " " ); + + + if (flags & (SYM_SET)) + strcat( ptr, "S" ); + else + strcat( ptr, " " ); + + if (flags & (SYM_MASREF|SYM_SET)) + { + strcat( ptr, ")" ); + } + else + strcat( ptr, " " ); + + + return ptr; +} + +void clearsegs(void) +{ + SEGMENT *seg; + + for (seg = Seglist; seg; seg = seg->next) { + seg->flags = (seg->flags & SF_BSS) | SF_UNKNOWN; + seg->rflags= seg->initflags = seg->initrflags = SF_UNKNOWN; + } +} + + +void clearrefs(void) +{ + SYMBOL *sym; + short i; + + for (i = 0; i < SHASHSIZE; ++i) + for (sym = SHash[i]; sym; sym = sym->next) + sym->flags &= ~SYM_REF; +} + + + + +char *cleanup(char *buf, bool bDisable) +{ + char *str; + STRLIST *strlist; + int arg, add; + char *comment = ""; + + for (str = buf; *str; ++str) + { + switch(*str) + { + case ';': + comment = (char *)str + 1; + /* FALL THROUGH */ + case '\r': + case '\n': + goto br2; + case TAB: + *str = ' '; + break; + case '\'': + ++str; + if (*str == TAB) + *str = ' '; + if (*str == '\n' || *str == 0) + { + str[0] = ' '; + str[1] = 0; + } + if (str[0] == ' ') + str[0] = '\x80'; + break; + case '\"': + ++str; + while (*str && *str != '\"') + { + if (*str == ' ') + *str = '\x80'; + ++str; + } + if (*str != '\"') + { + asmerr( ERROR_SYNTAX_ERROR, false, buf ); + --str; + } + break; + case '{': + if ( bDisable ) + break; + + if (Xdebug) + printf("macro tail: '%s'\n", str); + + arg = atoi(str+1); + for (add = 0; *str && *str != '}'; ++str) + --add; + if (*str != '}') + { + puts("end brace required"); + --str; + break; + } + --add; + ++str; + + + if (Xdebug) + printf("add/str: %d '%s'\n", add, str); + + for (strlist = pIncfile->args; arg && strlist;) + { + --arg; + strlist = strlist->next; + } + + if (strlist) + { + add += strlen(strlist->buf); + + if (Xdebug) + printf("strlist: '%s' %d\n", strlist->buf, strlen(strlist->buf)); + + if (str + add + strlen(str) + 1 > buf + MAXLINE) + { + if (Xdebug) + printf("str %8ld buf %8ld (add/strlen(str)): %d %ld\n", + (unsigned long)str, (unsigned long)buf, add, (long)strlen(str)); + panic("failure1"); + } + + memmove(str + add, str, strlen(str)+1); + str += add; + if (str - strlen(strlist->buf) < buf) + panic("failure2"); + memmove(str - strlen(strlist->buf), strlist->buf, strlen(strlist->buf)); + str -= strlen(strlist->buf); + if (str < buf || str >= buf + MAXLINE) + panic("failure 3"); + --str; /* for loop increments string */ + } + else + { + asmerr( ERROR_NOT_ENOUGH_ARGUMENTS_PASSED_TO_MACRO, false, NULL ); + goto br2; + } + break; + } + } + +br2: + while(str != buf && *(str-1) == ' ') + --str; + *str = 0; + + return comment; +} + +void panic(char *str) +{ + puts(str); + exit(1); +} + +/* +* .dir direct x +* .ext extended x +* .r relative x +* .x index, no offset x +* .x8 index, byte offset x +* .x16 index, word offset x +* .bit bit set/clr +* .bbr bit and branch +* .imp implied (inherent) x +* .b x +* .w x +* .l x +* .u x +*/ + + +void findext(char *str) +{ + Mnext = -1; + Extstr = NULL; + + if (str[0] == '.') { /* Allow .OP for OP */ + return; + } + + while (*str && *str != '.') + ++str; + if (*str) { + *str = 0; + ++str; + Extstr = str; + switch(str[0]|0x20) { + case '0': + case 'i': + Mnext = AM_IMP; + switch(str[1]|0x20) { + case 'x': + Mnext = AM_0X; + break; + case 'y': + Mnext = AM_0Y; + break; + case 'n': + Mnext = AM_INDWORD; + break; + } + return; + case 'd': + case 'b': + case 'z': + switch(str[1]|0x20) { + case 'x': + Mnext = AM_BYTEADRX; + break; + case 'y': + Mnext = AM_BYTEADRY; + break; + case 'i': + Mnext = AM_BITMOD; + break; + case 'b': + Mnext = AM_BITBRAMOD; + break; + default: + Mnext = AM_BYTEADR; + break; + } + return; + case 'e': + case 'w': + case 'a': + switch(str[1]|0x20) { + case 'x': + Mnext = AM_WORDADRX; + break; + case 'y': + Mnext = AM_WORDADRY; + break; + default: + Mnext = AM_WORDADR; + break; + } + return; + case 'l': + Mnext = AM_LONG; + return; + case 'r': + Mnext = AM_REL; + return; + case 'u': + Mnext = AM_BSS; + return; + } + } +} + +/* +* bytes arg will eventually be used to implement a linked list of free +* nodes. +* Assumes *base is really a pointer to a structure with .next as the first +* member. +*/ + +void rmnode(void **base, int bytes) +{ + void *node; + + if ((node = *base) != NULL) { + *base = *(void **)node; + free(node); + } +} + +/* +* Parse into three arguments: Av[0], Av[1], Av[2] +*/ +MNEMONIC *parse(char *buf) +{ + int i, j; + MNEMONIC *mne = NULL; + + i = 0; + j = 1; + +#if OlafFreeFormat + /* Skip all initial spaces */ + while (buf[i] == ' ') + ++i; +#endif + +#if OlafHashFormat + /* + * If the first non-space is a ^, skip all further spaces too. + * This means what follows is a label. + * If the first non-space is a #, what follows is a directive/opcode. + */ + while (buf[i] == ' ') + ++i; + if (buf[i] == '^') { + ++i; + while (buf[i] == ' ') + ++i; + } else if (buf[i] == '#') { + buf[i] = ' '; /* label separator */ + } else + i = 0; +#endif + + Av[0] = Avbuf + j; + while (buf[i] && buf[i] != ' ') { + + if (buf[i] == ':') { + i++; + break; + } + + if ((unsigned char)buf[i] == 0x80) + buf[i] = ' '; + Avbuf[j++] = buf[i++]; + } + Avbuf[j++] = 0; + +#if OlafFreeFormat + /* Try if the first word is an opcode */ + findext(Av[0]); + mne = findmne(Av[0]); + if (mne != NULL) { + /* Yes, it is. So there is no label, and the rest + * of the line is the argument + */ + Avbuf[0] = 0; /* Make an empty string */ + Av[1] = Av[0]; /* The opcode is the previous first word */ + Av[0] = Avbuf; /* Point the label to the empty string */ + } else +#endif + + { /* Parse the second word of the line */ + while (buf[i] == ' ') + ++i; + Av[1] = Avbuf + j; + while (buf[i] && buf[i] != ' ') { + if ((unsigned char)buf[i] == 0x80) + buf[i] = ' '; + Avbuf[j++] = buf[i++]; + } + Avbuf[j++] = 0; + /* and analyse it as an opcode */ + findext(Av[1]); + mne = findmne(Av[1]); + } + /* Parse the rest of the line */ + while (buf[i] == ' ') + ++i; + Av[2] = Avbuf + j; + while (buf[i]) { + if (buf[i] == ' ') { + while(buf[i+1] == ' ') + ++i; + } + if ((unsigned char)buf[i] == 0x80) + buf[i] = ' '; + Avbuf[j++] = buf[i++]; + } + Avbuf[j] = 0; + + return mne; +} + + + +MNEMONIC *findmne(char *str) +{ + int i; + char c; + MNEMONIC *mne; + char buf[64]; + + + if (str[0] == '.') { /* Allow .OP for OP */ + str++; + } + + for (i = 0; (c = str[i]); ++i) { + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + buf[i] = c; + } + buf[i] = 0; + for (mne = MHash[hash1(buf)]; mne; mne = mne->next) { + if (strcmp(buf, mne->name) == 0) + break; + } + return mne; +} + +void v_macro(char *str, MNEMONIC *dummy) +{ + STRLIST *base; + int defined = 0; + STRLIST **slp, *sl; + MACRO *mac; /* slp, mac: might be used uninitialised */ + MNEMONIC *mne; + unsigned int i; + char buf[MAXLINE]; + int skipit = !(Ifstack->xtrue && Ifstack->acctrue); + + strlower(str); + if (skipit) { + defined = 1; + } else { + defined = (findmne(str) != NULL); + if (F_listfile && ListMode) + outlistfile(""); + } + if (!defined) { + base = NULL; + slp = &base; + mac = (MACRO *)permalloc(sizeof(MACRO)); + i = hash1(str); + mac->next = (MACRO *)MHash[i]; + mac->vect = v_execmac; + mac->name = strcpy(permalloc(strlen(str)+1), str); + mac->flags = MF_MACRO; + MHash[i] = (MNEMONIC *)mac; + } + while (fgets(buf, MAXLINE, pIncfile->fi)) { + char *comment; + + if (Xdebug) + printf("%08lx %s\n", (unsigned long) pIncfile, buf); + + ++pIncfile->lineno; + + + comment = cleanup(buf, true); + + mne = parse(buf); + if (Av[1][0]) { + if (mne && mne->flags & MF_ENDM) { + if (!defined) + mac->strlist = base; + return; + } + } + if (!skipit && F_listfile && ListMode) + outlistfile(comment); + if (!defined) { + sl = (STRLIST *)permalloc(STRLISTSIZE+1+strlen(buf)); + strcpy(sl->buf, buf); + *slp = sl; + slp = &sl->next; + } + } + asmerr( ERROR_PREMATURE_EOF, true, NULL ); +} + + +void addhashtable(MNEMONIC *mne) +{ + int i, j; + unsigned int opcode[NUMOC]; + + for (; mne->vect; ++mne) { + memcpy(opcode, mne->opcode, sizeof(mne->opcode)); + for (i = j = 0; i < NUMOC; ++i) { + mne->opcode[i] = 0; /* not really needed */ + if (mne->okmask & (1L << i)) + mne->opcode[i] = opcode[j++]; + } + i = hash1(mne->name); + mne->next = MHash[i]; + MHash[i] = mne; + } +} + + +static unsigned int hash1(char *str) +{ + unsigned int result = 0; + + while (*str) + result = (result << 2) ^ *str++; + return result & MHASHAND; +} + +void pushinclude(char *str) +{ + INCFILE *inf; + FILE *fi; + + if ((fi = pfopen(str, "r")) != NULL) { + if (F_verbose > 1 && F_verbose != 5 ) + printf("%.*s Including file \"%s\"\n", Inclevel*4, "", str); + ++Inclevel; + + if (F_listfile) + fprintf(FI_listfile, "------- FILE %s LEVEL %d PASS %d\n", str, Inclevel, pass); + + inf = (INCFILE *)zmalloc(sizeof(INCFILE)); + inf->next = pIncfile; + inf->name = strcpy(ckmalloc(strlen(str)+1), str); + inf->fi = fi; + inf->lineno = 0; + pIncfile = inf; + return; + } + printf("Warning: Unable to open '%s'\n", str); + return; +} + + + + +int asmerr(int err, bool abort, char *sText ) +{ + char *str; + INCFILE *pincfile; + + if ( err >= MAX_ERROR || err < 0 ) + { + return asmerr( ERROR_BADERROR, true, "Bad error ERROR!" ); + } + else + { + + if (sErrorDef[err].bFatal) + bStopAtEnd = true; + + for ( pincfile = pIncfile; pincfile->flags & INF_MACRO; pincfile=pincfile->next); + str = sErrorDef[err].sDescription; + +#ifdef DAD + + /* Error output format changed to be Visual-Studio compatible. + Output now file (line): error: string + */ + + if (F_listfile) + { + fprintf(FI_listfile, "%s (%d): error: ", pincfile->name, pincfile->lineno ); + fprintf(FI_listfile, str, sText ? sText : "" ); + fprintf(FI_listfile, "\n" ); + } + printf( "%s (%d): error: ", pincfile->name, pincfile->lineno ); + printf( str, sText ? sText : "" ); + printf( "\n" ); + + +#else + + if (F_listfile) + fprintf(FI_listfile, "*line %7ld %-10s %s\n", pincfile->lineno, pincfile->name, str); + printf("line %7ld %-10s %s\n", pincfile->lineno, pincfile->name, str); + +#endif + + if ( abort ) + { + puts("Aborting assembly"); + if (F_listfile) + fputs("Aborting assembly\n", FI_listfile); + + exit( 1 ); + } + } + + return err; +} + +char *zmalloc(int bytes) +{ + char *ptr = ckmalloc(bytes); + if ( ptr ) + memset(ptr, 0, bytes); + return ptr; +} + +char *ckmalloc(int bytes) +{ + char *ptr = malloc(bytes); + if (ptr) + { + return ptr; + } + panic("unable to malloc"); + return NULL; +} + +char *permalloc(int bytes) +{ + static char *buf; + static int left; + char *ptr; + + /* Assume sizeof(union align) is a power of 2 */ + + union align + { + long l; + void *p; + void (*fp)(void); + }; + + bytes = (bytes + sizeof(union align)-1) & ~(sizeof(union align)-1); + if (bytes > left) + { + if ((buf = malloc(ALLOCSIZE)) == NULL) + panic("unable to malloc"); + memset(buf, 0, ALLOCSIZE); + left = ALLOCSIZE; + if (bytes > left) + panic("software error"); + } + ptr = buf; + buf += bytes; + left -= bytes; + return ptr; +} + +char *strlower(char *str) +{ + char c; + char *ptr; + + for (ptr = str; (c = *ptr); ++ptr) + { + if (c >= 'A' && c <= 'Z') + *ptr = c | 0x20; + } + return str; +} + +int main(int ac, char **av) +{ + bool bTableSort = false; + int nError = MainShadow( ac, av, &bTableSort ); + + if ( nError ) + printf( "Fatal assembly error: %s\n", sErrorDef[nError].sDescription ); + + DumpSymbolTable( bTableSort ); + + return nError; +} + diff --git a/src/mne6303.c b/src/mne6303.c new file mode 100644 index 00000000..0d3efe73 --- /dev/null +++ b/src/mne6303.c @@ -0,0 +1,176 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + * MNE6303.C + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + */ + +#include "asm.h" + +/* + * IMP IMM8 IMM16 BYTE BYTEX BYTEY WORD WORDX WORDY REL (,x) (),y (WORD) + * 0 1 2 3 4 5 6 7 8 9 10 11 12 + * + * 0,x 0,y BIT BITBRA + * 13 14 15 16 + */ + +MNEMONIC Mne6803[] = { + { NULL, v_mnemonic, "aba", 0, AF_IMP, { 0x1B }}, + { NULL, v_mnemonic, "abx", 0, AF_IMP, { 0x3A }}, + { NULL, v_mnemonic, "adca", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x89, 0x99, 0xA9, 0xB9 }}, + { NULL, v_mnemonic, "adcb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC9, 0xD9, 0xE9, 0xF9 }}, + { NULL, v_mnemonic, "adda", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x8B, 0x9B, 0xAB, 0xBB }}, + { NULL, v_mnemonic, "addb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xCB, 0xDB, 0xEB, 0xFB }}, + { NULL, v_mnemonic, "addd", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC3, 0xD3, 0xE3, 0xF3 }}, + { NULL, v_mnemonic, "anda", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x84, 0x94, 0xA4, 0xB4 }}, + { NULL, v_mnemonic, "andb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC4, 0xD4, 0xE4, 0xF4 }}, + { NULL, v_mnemonic, "bita", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x85, 0x95, 0xA5, 0xB5 }}, + { NULL, v_mnemonic, "bitb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC5, 0xD5, 0xE5, 0xF5 }}, + { NULL, v_mnemonic, "bra", 0, AF_REL, { 0x20 }}, + { NULL, v_mnemonic, "brn", 0, AF_REL, { 0x21 }}, + { NULL, v_mnemonic, "bcc", 0, AF_REL, { 0x24 }}, + { NULL, v_mnemonic, "bhs", 0, AF_REL, { 0x24 }}, + { NULL, v_mnemonic, "bcs", 0, AF_REL, { 0x25 }}, + { NULL, v_mnemonic, "blo", 0, AF_REL, { 0x25 }}, + { NULL, v_mnemonic, "beq", 0, AF_REL, { 0x27 }}, + { NULL, v_mnemonic, "bge", 0, AF_REL, { 0x2C }}, + { NULL, v_mnemonic, "bgt", 0, AF_REL, { 0x2E }}, + { NULL, v_mnemonic, "bhi", 0, AF_REL, { 0x22 }}, + { NULL, v_mnemonic, "ble", 0, AF_REL, { 0x2F }}, + { NULL, v_mnemonic, "bls", 0, AF_REL, { 0x23 }}, + { NULL, v_mnemonic, "blt", 0, AF_REL, { 0x2D }}, + { NULL, v_mnemonic, "bmi", 0, AF_REL, { 0x2B }}, + { NULL, v_mnemonic, "bne", 0, AF_REL, { 0x26 }}, + { NULL, v_mnemonic, "bvc", 0, AF_REL, { 0x28 }}, + { NULL, v_mnemonic, "bvs", 0, AF_REL, { 0x29 }}, + { NULL, v_mnemonic, "bpl", 0, AF_REL, { 0x2A }}, + { NULL, v_mnemonic, "bsr", 0, AF_REL, { 0x8D }}, + { NULL, v_mnemonic, "clc", 0, AF_IMP, { 0x0C }}, + { NULL, v_mnemonic, "cli", 0, AF_IMP, { 0x0E }}, + { NULL, v_mnemonic, "clv", 0, AF_IMP, { 0x0A }}, + { NULL, v_mnemonic, "sec", 0, AF_IMP, { 0x0D }}, + { NULL, v_mnemonic, "sei", 0, AF_IMP, { 0x0F }}, + { NULL, v_mnemonic, "sev", 0, AF_IMP, { 0x0B }}, + { NULL, v_mnemonic, "tap", 0, AF_IMP, { 0x06 }}, + { NULL, v_mnemonic, "tpa", 0, AF_IMP, { 0x07 }}, + { NULL, v_mnemonic, "clr", 0, AF_BYTEADRX|AF_WORDADR, { 0x6F, 0x7F }}, + { NULL, v_mnemonic, "clra", 0, AF_IMP, { 0x4F }}, + { NULL, v_mnemonic, "clrb", 0, AF_IMP, { 0x5F }}, + { NULL, v_mnemonic, "cmpa", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x81, 0x91, 0xA1, 0xB1 }}, + { NULL, v_mnemonic, "cmpb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC1, 0xD1, 0xE1, 0xF1 }}, + { NULL, v_mnemonic, "cba", 0, AF_IMP, { 0x11 }}, + { NULL, v_mnemonic, "com", 0, AF_BYTEADRX|AF_WORDADR, { 0x63, 0x73 }}, + { NULL, v_mnemonic, "coma", 0, AF_IMP, { 0x43 }}, + { NULL, v_mnemonic, "comb", 0, AF_IMP, { 0x53 }}, + { NULL, v_mnemonic, "neg", 0, AF_BYTEADRX|AF_WORDADR, { 0x60, 0x70 }}, + { NULL, v_mnemonic, "nega", 0, AF_IMP, { 0x40 }}, + { NULL, v_mnemonic, "negb", 0, AF_IMP, { 0x50 }}, + { NULL, v_mnemonic, "daa", 0, AF_IMP, { 0x19 }}, + { NULL, v_mnemonic, "dec", 0, AF_BYTEADRX|AF_WORDADR, { 0x6A, 0x7A }}, + { NULL, v_mnemonic, "deca", 0, AF_IMP, { 0x4A }}, + { NULL, v_mnemonic, "decb", 0, AF_IMP, { 0x5A }}, + { NULL, v_mnemonic, "eora", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x88, 0x98, 0xA8, 0xB8 }}, + { NULL, v_mnemonic, "eorb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC8, 0xD8, 0xE8, 0xF8 }}, + { NULL, v_mnemonic, "inc", 0, AF_BYTEADRX|AF_WORDADR, { 0x6C, 0x7C }}, + { NULL, v_mnemonic, "inca", 0, AF_IMP, { 0x4C }}, + { NULL, v_mnemonic, "incb", 0, AF_IMP, { 0x5C }}, + { NULL, v_mnemonic, "jmp", 0, AF_BYTEADRX|AF_WORDADR, { 0x6E, 0x7E }}, + { NULL, v_mnemonic, "jsr", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x9D, 0xAD, 0xBD }}, + { NULL, v_mnemonic, "ldaa", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x86, 0x96, 0xA6, 0xB6 }}, + { NULL, v_mnemonic, "ldab", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC6, 0xD6, 0xE6, 0xF6 }}, + { NULL, v_mnemonic, "ldd", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xCC, 0xDC, 0xEC, 0xFC }}, + { NULL, v_mnemonic, "mul", 0, AF_IMP, { 0x3D }}, + { NULL, v_mnemonic, "nop", 0, AF_IMP, { 0x01 }}, + { NULL, v_mnemonic, "oraa",0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x8A, 0x9A, 0xAA, 0xBA }}, + { NULL, v_mnemonic, "orab", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xCA, 0xDA, 0xEA, 0xFA }}, + { NULL, v_mnemonic, "psha", 0, AF_IMP, { 0x36 }}, + { NULL, v_mnemonic, "pshb", 0, AF_IMP, { 0x37 }}, + { NULL, v_mnemonic, "pshx", 0, AF_IMP, { 0x3C }}, + { NULL, v_mnemonic, "pulx", 0, AF_IMP, { 0x38 }}, + { NULL, v_mnemonic, "pula", 0, AF_IMP, { 0x32 }}, + { NULL, v_mnemonic, "pulb", 0, AF_IMP, { 0x33 }}, + { NULL, v_mnemonic, "rol", 0, AF_BYTEADRX|AF_WORDADR, { 0x69, 0x79 }}, + { NULL, v_mnemonic, "rola", 0, AF_IMP, { 0x49 }}, + { NULL, v_mnemonic, "rolb", 0, AF_IMP, { 0x59 }}, + { NULL, v_mnemonic, "ror", 0, AF_BYTEADRX|AF_WORDADR, { 0x66, 0x76 }}, + { NULL, v_mnemonic, "rora", 0, AF_IMP, { 0x46 }}, + { NULL, v_mnemonic, "rorb", 0, AF_IMP, { 0x56 }}, + { NULL, v_mnemonic, "rti", 0, AF_IMP, { 0x3B }}, + { NULL, v_mnemonic, "rts", 0, AF_IMP, { 0x39 }}, + { NULL, v_mnemonic, "swi", 0, AF_IMP, { 0x3F }}, + { NULL, v_mnemonic, "wai", 0, AF_IMP, { 0x3E }}, + { NULL, v_mnemonic, "asl", 0, AF_BYTEADRX|AF_WORDADR, { 0x68, 0x78 }}, + { NULL, v_mnemonic, "lsl", 0, AF_BYTEADRX|AF_WORDADR, { 0x68, 0x78 }}, + { NULL, v_mnemonic, "asla", 0, AF_IMP, { 0x48 }}, + { NULL, v_mnemonic, "aslb", 0, AF_IMP, { 0x58 }}, + { NULL, v_mnemonic, "asld", 0, AF_IMP, { 0x05 }}, + { NULL, v_mnemonic, "lsla", 0, AF_IMP, { 0x48 }}, /* same thing */ + { NULL, v_mnemonic, "lslb", 0, AF_IMP, { 0x58 }}, + { NULL, v_mnemonic, "lsld", 0, AF_IMP, { 0x05 }}, + { NULL, v_mnemonic, "asr", 0, AF_BYTEADRX|AF_WORDADR, { 0x67, 0x77 }}, + { NULL, v_mnemonic, "asra", 0, AF_IMP, { 0x47 }}, + { NULL, v_mnemonic, "asrb", 0, AF_IMP, { 0x57 }}, + { NULL, v_mnemonic, "cpx", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x8C, 0x9C, 0xAC, 0xBC }}, + { NULL, v_mnemonic, "dex", 0, AF_IMP, { 0x09 }}, + { NULL, v_mnemonic, "des", 0, AF_IMP, { 0x34 }}, + { NULL, v_mnemonic, "inx", 0, AF_IMP, { 0x08 }}, + { NULL, v_mnemonic, "ins", 0, AF_IMP, { 0x31 }}, + { NULL, v_mnemonic, "ldx", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xCE, 0xDE, 0xEE, 0xFE }}, + { NULL, v_mnemonic, "lds", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x8E, 0x9E, 0xAE, 0xBE }}, + { NULL, v_mnemonic, "lsr", 0, AF_BYTEADRX|AF_WORDADR, { 0x64, 0x74 }}, + { NULL, v_mnemonic, "lsra", 0, AF_IMP, { 0x44 }}, + { NULL, v_mnemonic, "lsrb", 0, AF_IMP, { 0x54 }}, + { NULL, v_mnemonic, "lsrd", 0, AF_IMP, { 0x04 }}, + { NULL, v_mnemonic, "staa", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x97, 0xA7, 0xB7 }}, + { NULL, v_mnemonic, "stab", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xD7, 0xE7, 0xF7 }}, + { NULL, v_mnemonic, "std", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xDD, 0xED, 0xFD }}, + { NULL, v_mnemonic, "sts", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x9F, 0xAF, 0xBF }}, + { NULL, v_mnemonic, "stx", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xDF, 0xEF, 0xFF }}, + { NULL, v_mnemonic, "suba", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x80, 0x90, 0xA0, 0xB0 }}, + { NULL, v_mnemonic, "subb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC0, 0xD0, 0xE0, 0xF0 }}, + { NULL, v_mnemonic, "subd", 0, AF_IMM16|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x83, 0x93, 0xA3, 0xB3 }}, + { NULL, v_mnemonic, "sba", 0, AF_IMP, { 0x10 }}, + { NULL, v_mnemonic, "sbca", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x82, 0x92, 0xA2, 0xB2 }}, + { NULL, v_mnemonic, "sbcb", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0xC2, 0xD2, 0xE2, 0xF2 }}, + { NULL, v_mnemonic, "tab", 0, AF_IMP, { 0x16 }}, + { NULL, v_mnemonic, "tba", 0, AF_IMP, { 0x17 }}, + { NULL, v_mnemonic, "tst", 0, AF_BYTEADRX|AF_WORDADR, { 0x6D, 0x7D }}, + { NULL, v_mnemonic, "tsta", 0, AF_IMP, { 0x4D }}, + { NULL, v_mnemonic, "tstb", 0, AF_IMP, { 0x5D }}, + { NULL, v_mnemonic, "tsx", 0, AF_IMP, { 0x30 }}, + { NULL, v_mnemonic, "txs", 0, AF_IMP, { 0x35 }}, + NULL +}; + +MNEMONIC MneHD6303[] = { + { NULL, v_mnemonic, "slp", 0, AF_IMP, { 0x1A }}, + { NULL, v_mnemonic, "aim", 0, AF_BYTEADR|AF_BYTEADRX, { 0x71, 0x61 }}, + { NULL, v_mnemonic, "oim", 0, AF_BYTEADR|AF_BYTEADRX, { 0x72, 0x62 }}, + { NULL, v_mnemonic, "eim", 0, AF_BYTEADR|AF_BYTEADRX, { 0x75, 0x65 }}, + { NULL, v_mnemonic, "tim", 0, AF_BYTEADR|AF_BYTEADRX, { 0x7B, 0x6B }}, + { NULL, v_mnemonic, "xgdx", 0, AF_IMP, { 0x18 }}, + NULL +}; + + diff --git a/src/mne6502.c b/src/mne6502.c new file mode 100644 index 00000000..03ff3edd --- /dev/null +++ b/src/mne6502.c @@ -0,0 +1,107 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + #include "asm.h" + +#define ASTD AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|\ + AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY + +MNEMONIC Mne6502[] = { + { NULL, v_mnemonic, "adc", 0, AF_IMM8|ASTD, { 0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71 } }, + { NULL, v_mnemonic, "anc", 0, AF_IMM8, { 0x0b } }, + { NULL, v_mnemonic, "and", 0, AF_IMM8|ASTD, { 0x29, 0x25, 0x35, 0x2D, 0x3D, 0x39, 0x21, 0x31 } }, + { NULL, v_mnemonic, "ane", 0, AF_IMM8, { 0x8b } }, + { NULL, v_mnemonic, "arr", 0, AF_IMM8, { 0x6b } }, + { NULL, v_mnemonic, "asl", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0x0A, 0x06, 0x16, 0x0E, 0x1E } }, + { NULL, v_mnemonic, "asr", 0, AF_IMM8, { 0x4b } }, + { NULL, v_mnemonic, "bcc", 0, AF_REL, { 0x90 } }, + { NULL, v_mnemonic, "bcs", 0, AF_REL, { 0xB0 } }, + { NULL, v_mnemonic, "beq", 0, AF_REL, { 0xF0 } }, + { NULL, v_mnemonic, "bit", 0, AF_BYTEADR|AF_WORDADR, { 0x24, 0x2C } }, + { NULL, v_mnemonic, "bmi", 0, AF_REL, { 0x30 } }, + { NULL, v_mnemonic, "bne", 0, AF_REL, { 0xD0 } }, + { NULL, v_mnemonic, "bpl", 0, AF_REL, { 0x10 } }, + { NULL, v_mnemonic, "brk", 0, AF_IMP, { 0x00 } }, + { NULL, v_mnemonic, "bvc", 0, AF_REL, { 0x50 } }, + { NULL, v_mnemonic, "bvs", 0, AF_REL, { 0x70 } }, + { NULL, v_mnemonic, "clc", 0, AF_IMP, { 0x18 } }, + { NULL, v_mnemonic, "cld", 0, AF_IMP, { 0xD8 } }, + { NULL, v_mnemonic, "cli", 0, AF_IMP, { 0x58 } }, + { NULL, v_mnemonic, "clv", 0, AF_IMP, { 0xB8 } }, + { NULL, v_mnemonic, "cmp", 0, AF_IMM8|ASTD, { 0xC9, 0xC5, 0xD5, 0xCD, 0xDD, 0xD9, 0xC1, 0xD1 } }, + { NULL, v_mnemonic, "cpx", 0, AF_IMM8|AF_BYTEADR|AF_WORDADR, { 0xE0, 0xE4, 0xEC } }, + { NULL, v_mnemonic, "cpy", 0, AF_IMM8|AF_BYTEADR|AF_WORDADR, { 0xC0, 0xC4, 0xCC } }, + { NULL, v_mnemonic, "dcp", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0xc7, 0xd7, 0xcf, 0xdf, 0xdb, 0xc3, 0xd3 } }, + { NULL, v_mnemonic, "dec", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0xC6, 0xD6, 0xCE, 0xDE } }, + { NULL, v_mnemonic, "dex", 0, AF_IMP, { 0xCA } }, + { NULL, v_mnemonic, "dey", 0, AF_IMP, { 0x88 } }, + { NULL, v_mnemonic, "eor", 0, AF_IMM8|ASTD, { 0x49, 0x45, 0x55, 0x4D, 0x5D, 0x59, 0x41,0x51 } }, + { NULL, v_mnemonic, "inc", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0xE6, 0xF6, 0xEE, 0xFE } }, + { NULL, v_mnemonic, "inx", 0, AF_IMP, { 0xE8 } }, + { NULL, v_mnemonic, "iny", 0, AF_IMP, { 0xC8 } }, + { NULL, v_mnemonic, "isb", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0xe7, 0xf7, 0xef, 0xff, 0xfb, 0xe3, 0xf3 } }, + { NULL, v_mnemonic, "jmp", 0, AF_WORDADR|AF_INDWORD, { 0x4C, 0x6C } }, + { NULL, v_mnemonic, "jsr", 0, AF_WORDADR, { 0x20 } }, + { NULL, v_mnemonic, "las", 0, AF_WORDADRY, { 0xbb } }, + { NULL, v_mnemonic, "lax", 0, AF_BYTEADR|AF_BYTEADRY|AF_WORDADR|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0xa7, 0xb7, 0xaf, 0xbf, 0xa3, 0xb3 } }, + { NULL, v_mnemonic, "lda", 0, AF_IMM8|ASTD, { 0xA9, 0xA5, 0xB5, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1 } }, + { NULL, v_mnemonic, "ldx", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRY|AF_WORDADR|AF_WORDADRY, { 0xA2, 0xA6, 0xB6, 0xAE, 0xBE } }, + { NULL, v_mnemonic, "ldy", 0, AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0xA0, 0xA4, 0xB4, 0xAC, 0xBC } }, + { NULL, v_mnemonic, "lsr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0x4A, 0x46, 0x56, 0x4E, 0x5E } }, + { NULL, v_mnemonic, "lxa", 0, AF_IMM8, { 0xab } }, + { NULL, v_mnemonic, "nop", 0, AF_IMP|AF_IMM8|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0xEA, 0x80, 0x04, 0x14, 0x0c, 0x1c } }, + { NULL, v_mnemonic, "ora", 0, AF_IMM8|ASTD, { 0x09, 0x05, 0x15, 0x0D, 0x1D, 0x19, 0x01, 0x11 } }, + { NULL, v_mnemonic, "pha", 0, AF_IMP, { 0x48 } }, + { NULL, v_mnemonic, "php", 0, AF_IMP, { 0x08 } }, + { NULL, v_mnemonic, "pla", 0, AF_IMP, { 0x68 } }, + { NULL, v_mnemonic, "plp", 0, AF_IMP, { 0x28 } }, + { NULL, v_mnemonic, "rla", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0x27, 0x37, 0x2f, 0x3f, 0x3b, 0x23, 0x33 } }, + { NULL, v_mnemonic, "rol", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0x2A, 0x26, 0x36, 0x2E, 0x3E } }, + { NULL, v_mnemonic, "ror", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX, { 0x6A, 0x66, 0x76, 0x6E, 0x7E } }, + { NULL, v_mnemonic, "rra", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0x67, 0x77, 0x6f, 0x7f, 0x7b, 0x63, 0x73 } }, + { NULL, v_mnemonic, "rti", 0, AF_IMP, { 0x40 } }, + { NULL, v_mnemonic, "rts", 0, AF_IMP, { 0x60 } }, + { NULL, v_mnemonic, "sax", 0, AF_BYTEADR|AF_BYTEADRY|AF_WORDADR|AF_INDBYTEX, { 0x87, 0x97, 0x8f, 0x83 } }, + { NULL, v_mnemonic, "sbc", 0, AF_IMM8|ASTD, { 0xE9, 0xE5, 0xF5, 0xED, 0xFD, 0xF9, 0xE1, 0xF1 } }, + { NULL, v_mnemonic, "sbx", 0, AF_IMM8, { 0xcb } }, + { NULL, v_mnemonic, "sec", 0, AF_IMP, { 0x38 } }, + { NULL, v_mnemonic, "sed", 0, AF_IMP, { 0xF8 } }, + { NULL, v_mnemonic, "sei", 0, AF_IMP, { 0x78 } }, + { NULL, v_mnemonic, "sha", 0, AF_WORDADRY|AF_INDBYTEY, { 0x9f, 0x93 } }, + { NULL, v_mnemonic, "shs", 0, AF_WORDADRY, { 0x9b } }, + { NULL, v_mnemonic, "shx", 0, AF_WORDADRY, { 0x9e } }, + { NULL, v_mnemonic, "shy", 0, AF_WORDADRX, { 0x9c } }, + { NULL, v_mnemonic, "slo", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0x07, 0x17, 0x0f, 0x1f, 0x1b, 0x03, 0x13 } }, + { NULL, v_mnemonic, "sre", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_WORDADRY|AF_INDBYTEX|AF_INDBYTEY, { 0x47, 0x57, 0x4f, 0x5f, 0x5b, 0x43, 0x53 } }, + { NULL, v_mnemonic, "sta", 0, ASTD, { 0x85, 0x95, 0x8D, 0x9D, 0x99, 0x81, 0x91 } }, + { NULL, v_mnemonic, "stx", 0, AF_BYTEADR|AF_BYTEADRY|AF_WORDADR, { 0x86, 0x96, 0x8E } }, + { NULL, v_mnemonic, "sty", 0, AF_BYTEADR|AF_BYTEADRX|AF_WORDADR, { 0x84, 0x94, 0x8C } }, + { NULL, v_mnemonic, "tax", 0, AF_IMP, { 0xAA } }, + { NULL, v_mnemonic, "tay", 0, AF_IMP, { 0xA8 } }, + { NULL, v_mnemonic, "tsx", 0, AF_IMP, { 0xBA } }, + { NULL, v_mnemonic, "txa", 0, AF_IMP, { 0x8A } }, + { NULL, v_mnemonic, "txs", 0, AF_IMP, { 0x9A } }, + { NULL, v_mnemonic, "tya", 0, AF_IMP, { 0x98 } }, + { NULL, } +}; + + + diff --git a/src/mne6811.c b/src/mne6811.c new file mode 100644 index 00000000..8b4ad84d --- /dev/null +++ b/src/mne6811.c @@ -0,0 +1,183 @@ + +/* + * MNE6811.C + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + * + * 68HC11 processor + * + * addressing modes: + * AF_IMM8 + * AF_IMM16 + * AF_BYTEADR + * AF_WORDADR + * AF_BYTEADRX + * AF_BYTEADRY + * AF_IMP + * AF_REL + * + * flags: + * MF_MASK contains additional byte argument + * MF_REL contains additional relative argument + */ + +#include "asm.h" + +#define AF_STD (AF_BYTEADR|AF_BYTEADRX|AF_BYTEADRY|AF_WORDADR) +#define AF_STDI (AF_IMM8|AF_STD) +#define AF_STDD (AF_IMM16|AF_STD) +#define AF_ASL (AF_BYTEADRX|AF_BYTEADRY|AF_WORDADR) +#define AF_BCLR (AF_BYTEADR|AF_BYTEADRX|AF_BYTEADRY) + +MNEMONIC Mne68HC11[] = { + { NULL, v_mnemonic, "aba", 0, AF_IMP, { 0x1B } }, + { NULL, v_mnemonic, "abx", 0, AF_IMP, { 0x3A } }, + { NULL, v_mnemonic, "aby", 0, AF_IMP, { 0x183A } }, + { NULL, v_mnemonic, "adca", 0, AF_STDI,{ 0x89, 0x99, 0xA9, 0x18A9, 0xB9 } }, + { NULL, v_mnemonic, "adcb", 0, AF_STDI,{ 0xC9, 0xD9, 0xE9, 0x18E9, 0xF9 } }, + { NULL, v_mnemonic, "adda", 0, AF_STDI,{ 0x8B, 0x9B, 0xAB, 0x18AB, 0xBB } }, + { NULL, v_mnemonic, "addb", 0, AF_STDI,{ 0xCB, 0xDB, 0xEB, 0x18EB, 0xFB } }, + { NULL, v_mnemonic, "addd", 0, AF_STDD,{ 0xC3, 0xD3, 0xE3, 0x18E3, 0xF3 } }, + { NULL, v_mnemonic, "anda", 0, AF_STDI,{ 0x84, 0x94, 0xA4, 0x18A4, 0xB4 } }, + { NULL, v_mnemonic, "andb", 0, AF_STDI,{ 0xC4, 0xD4, 0xE4, 0x18E4, 0xF4 } }, + { NULL, v_mnemonic, "asla", 0, AF_IMP, { 0x48 } }, + { NULL, v_mnemonic, "aslb", 0, AF_IMP, { 0x58 } }, + { NULL, v_mnemonic, "asl", 0, AF_ASL, { 0x68, 0x1868, 0x78 } }, + { NULL, v_mnemonic, "asld", 0, AF_IMP, { 0x05 } }, + { NULL, v_mnemonic, "asra", 0, AF_IMP, { 0x47 } }, + { NULL, v_mnemonic, "asrb", 0, AF_IMP, { 0x57 } }, + { NULL, v_mnemonic, "asr", 0, AF_ASL, { 0x67, 0x1867, 0x77 } }, + /* no asrd */ + { NULL, v_mnemonic, "bcc", 0, AF_REL, { 0x24 } }, + { NULL, v_mnemonic, "bclr", MF_MASK, AF_BCLR, { 0x15, 0x1D, 0x181D } }, + { NULL, v_mnemonic, "bcs", 0, AF_REL, { 0x25 } }, + { NULL, v_mnemonic, "beq", 0, AF_REL, { 0x27 } }, + { NULL, v_mnemonic, "bge", 0, AF_REL, { 0x2C } }, + { NULL, v_mnemonic, "bgt", 0, AF_REL, { 0x2E } }, + { NULL, v_mnemonic, "bhi", 0, AF_REL, { 0x22 } }, + { NULL, v_mnemonic, "bhs", 0, AF_REL, { 0x24 } }, + { NULL, v_mnemonic, "bita", 0, AF_STDI,{ 0x85, 0x95, 0xA5, 0x18A5, 0xB5 } }, + { NULL, v_mnemonic, "bitb", 0, AF_STDI,{ 0xC5, 0xD5, 0xE5, 0x18E5, 0xF5 } }, + { NULL, v_mnemonic, "ble", 0, AF_REL, { 0x2F } }, + { NULL, v_mnemonic, "blo", 0, AF_REL, { 0x25 } }, + { NULL, v_mnemonic, "bls", 0, AF_REL, { 0x23 } }, + { NULL, v_mnemonic, "blt", 0, AF_REL, { 0x2D } }, + { NULL, v_mnemonic, "bmi", 0, AF_REL, { 0x2B } }, + { NULL, v_mnemonic, "bne", 0, AF_REL, { 0x26 } }, + { NULL, v_mnemonic, "bpl", 0, AF_REL, { 0x2A } }, + { NULL, v_mnemonic, "bra", 0, AF_REL, { 0x20 } }, + { NULL, v_mnemonic, "brclr", MF_MASK|MF_REL, AF_BCLR,{ 0x13, 0x1F, 0x181F } }, + { NULL, v_mnemonic, "brn", 0, AF_REL, { 0x21 } }, + { NULL, v_mnemonic, "brset", MF_MASK|MF_REL, AF_BCLR,{ 0x12, 0x1E, 0x181E } }, + { NULL, v_mnemonic, "bset", MF_MASK, AF_BCLR, { 0x14, 0x1C, 0x181C } }, + { NULL, v_mnemonic, "bsr", 0, AF_REL, { 0x8D } }, + { NULL, v_mnemonic, "bvc", 0, AF_REL, { 0x28 } }, + { NULL, v_mnemonic, "bvs", 0, AF_REL, { 0x29 } }, + { NULL, v_mnemonic, "cba", 0, AF_IMP, { 0x11 } }, + { NULL, v_mnemonic, "clc", 0, AF_IMP, { 0x0C } }, + { NULL, v_mnemonic, "cli", 0, AF_IMP, { 0x0E } }, + { NULL, v_mnemonic, "clra", 0, AF_IMP, { 0x4F } }, + { NULL, v_mnemonic, "clrb", 0, AF_IMP, { 0x5F } }, + { NULL, v_mnemonic, "clr", 0, AF_ASL, { 0x6F, 0x186F, 0x7F } }, + { NULL, v_mnemonic, "clv", 0, AF_IMP, { 0x0A } }, + { NULL, v_mnemonic, "cmpa", 0, AF_STDI,{ 0x81, 0x91, 0xA1, 0x18A1, 0xB1 } }, + { NULL, v_mnemonic, "cmpb", 0, AF_STDI,{ 0xC1, 0xD1, 0xE1, 0x18E1, 0xF1 } }, + { NULL, v_mnemonic, "coma", 0, AF_IMP, { 0x43 } }, + { NULL, v_mnemonic, "comb", 0, AF_IMP, { 0x53 } }, + { NULL, v_mnemonic, "com", 0, AF_ASL, { 0x63, 0x1863, 0x73 } }, + { NULL, v_mnemonic, "cpd", 0, AF_STDD,{ 0x1A83, 0x1A93, 0x1AA3, 0xCDA3, 0x1AB3 } }, + { NULL, v_mnemonic, "cpx", 0, AF_STDD,{ 0x8C, 0x9C, 0xAC, 0xCDAC, 0xBC } }, + { NULL, v_mnemonic, "cpy", 0, AF_STDD,{ 0x188C, 0x189C, 0x1AAC, 0x18AC, 0x18BC } }, + { NULL, v_mnemonic, "daa", 0, AF_IMP, { 0x19 } }, + { NULL, v_mnemonic, "deca", 0, AF_IMP, { 0x4A } }, + { NULL, v_mnemonic, "decb", 0, AF_IMP, { 0x5A } }, + { NULL, v_mnemonic, "dec", 0, AF_ASL, { 0x6A, 0x186A, 0x7A } }, + { NULL, v_mnemonic, "des", 0, AF_IMP, { 0x34 } }, + { NULL, v_mnemonic, "dex", 0, AF_IMP, { 0x09 } }, + { NULL, v_mnemonic, "dey", 0, AF_IMP, { 0x1809 } }, + { NULL, v_mnemonic, "eora", 0, AF_STDI,{ 0x88, 0x98, 0xA8, 0x18A8, 0xB8 } }, + { NULL, v_mnemonic, "eorb", 0, AF_STDI,{ 0xC8, 0xD8, 0xE8, 0x18E8, 0xF8 } }, + { NULL, v_mnemonic, "fdiv", 0, AF_IMP, { 0x03 } }, + { NULL, v_mnemonic, "idiv", 0, AF_IMP, { 0x02 } }, + { NULL, v_mnemonic, "inca", 0, AF_IMP, { 0x4C } }, + { NULL, v_mnemonic, "incb", 0, AF_IMP, { 0x5C } }, + { NULL, v_mnemonic, "inc", 0, AF_ASL, { 0x6C, 0x186C, 0x7C } }, + { NULL, v_mnemonic, "ins", 0, AF_IMP, { 0x31 } }, + { NULL, v_mnemonic, "inx", 0, AF_IMP, { 0x08 } }, + { NULL, v_mnemonic, "iny", 0, AF_IMP, { 0x1808 } }, + { NULL, v_mnemonic, "jmp", 0, AF_ASL, { 0x6E, 0x186E, 0x7E } }, + { NULL, v_mnemonic, "jsr", 0, AF_STD, { 0x9D, 0xAD, 0x18AD, 0xBD } }, + { NULL, v_mnemonic, "ldaa", 0, AF_STDI,{ 0x86, 0x96, 0xA6, 0x18A6, 0xB6 } }, + { NULL, v_mnemonic, "ldab", 0, AF_STDI,{ 0xC6, 0xD6, 0xE6, 0x18E6, 0xF6 } }, + { NULL, v_mnemonic, "ldd", 0, AF_STDD,{ 0xCC, 0xDC, 0xEC, 0x18EC, 0xFC } }, + { NULL, v_mnemonic, "lds", 0, AF_STDD,{ 0x8E, 0x9E, 0xAE, 0x18AE, 0xBE } }, + { NULL, v_mnemonic, "ldx", 0, AF_STDD,{ 0xCE, 0xDE, 0xEE, 0xCDEE, 0xFE } }, + { NULL, v_mnemonic, "ldy", 0, AF_STDD,{ 0x18CE, 0x18DE, 0x1AEE, 0x18EE, 0x18FE } }, + { NULL, v_mnemonic, "lsla", 0, AF_IMP, { 0x48 } }, + { NULL, v_mnemonic, "lslb", 0, AF_IMP, { 0x58 } }, + { NULL, v_mnemonic, "lsl", 0, AF_ASL, { 0x68, 0x1868, 0x78 } }, + { NULL, v_mnemonic, "lsld", 0, AF_IMP, { 0x05 } }, + { NULL, v_mnemonic, "lsra", 0, AF_IMP, { 0x44 } }, + { NULL, v_mnemonic, "lsrb", 0, AF_IMP, { 0x54 } }, + { NULL, v_mnemonic, "lsr", 0, AF_ASL, { 0x64, 0x1864, 0x74 } }, + { NULL, v_mnemonic, "lsrd", 0, AF_IMP, { 0x04 } }, + { NULL, v_mnemonic, "mul", 0, AF_IMP, { 0x3D } }, + { NULL, v_mnemonic, "nega", 0, AF_IMP, { 0x40 } }, + { NULL, v_mnemonic, "negb", 0, AF_IMP, { 0x50 } }, + { NULL, v_mnemonic, "neg", 0, AF_ASL, { 0x60, 0x1860, 0x70 } }, + { NULL, v_mnemonic, "nop", 0, AF_IMP, { 0x01 } }, + { NULL, v_mnemonic, "oraa", 0, AF_STDI,{ 0x8A, 0x9A, 0xAA, 0x18AA, 0xBA } }, + { NULL, v_mnemonic, "orab", 0, AF_STDI,{ 0xCA, 0xDA, 0xEA, 0x18EA, 0xFA } }, + { NULL, v_mnemonic, "psha", 0, AF_IMP, { 0x36 } }, + { NULL, v_mnemonic, "pshb", 0, AF_IMP, { 0x37 } }, + { NULL, v_mnemonic, "pshx", 0, AF_IMP, { 0x3C } }, + { NULL, v_mnemonic, "pshy", 0, AF_IMP, { 0x183C } }, + { NULL, v_mnemonic, "pula", 0, AF_IMP, { 0x32 } }, + { NULL, v_mnemonic, "pulb", 0, AF_IMP, { 0x33 } }, + { NULL, v_mnemonic, "pulx", 0, AF_IMP, { 0x38 } }, + { NULL, v_mnemonic, "puly", 0, AF_IMP, { 0x1838 } }, + { NULL, v_mnemonic, "rola", 0, AF_IMP, { 0x49 } }, + { NULL, v_mnemonic, "rolb", 0, AF_IMP, { 0x59 } }, + { NULL, v_mnemonic, "rol", 0, AF_ASL, { 0x69, 0x1869, 0x79 } }, + { NULL, v_mnemonic, "rora", 0, AF_IMP, { 0x46 } }, + { NULL, v_mnemonic, "rorb", 0, AF_IMP, { 0x56 } }, + { NULL, v_mnemonic, "ror", 0, AF_ASL, { 0x66, 0x1866, 0x76 } }, + { NULL, v_mnemonic, "rti", 0, AF_IMP, { 0x3B } }, + { NULL, v_mnemonic, "rts", 0, AF_IMP, { 0x39 } }, + { NULL, v_mnemonic, "sba", 0, AF_IMP, { 0x10 } }, + { NULL, v_mnemonic, "sbca", 0, AF_STDI,{ 0x82, 0x92, 0xA2, 0x18A2, 0xB2 } }, + { NULL, v_mnemonic, "sbcb", 0, AF_STDI,{ 0xC2, 0xD2, 0xE2, 0x18E2, 0xF2 } }, + { NULL, v_mnemonic, "sec", 0, AF_IMP, { 0x0D } }, + { NULL, v_mnemonic, "sei", 0, AF_IMP, { 0x0F } }, + { NULL, v_mnemonic, "sev", 0, AF_IMP, { 0x0B } }, + { NULL, v_mnemonic, "staa", 0, AF_STD, { 0x97, 0xA7, 0x18A7, 0xB7 } }, + { NULL, v_mnemonic, "stab", 0, AF_STD, { 0xD7, 0xE7, 0x18E7, 0xF7 } }, + { NULL, v_mnemonic, "std", 0, AF_STD, { 0xDD, 0xED, 0x18ED, 0xFD } }, + { NULL, v_mnemonic, "stop", 0, AF_IMP, { 0xCF } }, + { NULL, v_mnemonic, "sts", 0, AF_STD, { 0x9F, 0xAF, 0x18AF, 0xBF } }, + { NULL, v_mnemonic, "stx", 0, AF_STD, { 0xDF, 0xEF, 0xCDEF, 0xFF } }, + { NULL, v_mnemonic, "sty", 0, AF_STD, { 0x18DF, 0x1AEF, 0x18EF, 0x18FF } }, + { NULL, v_mnemonic, "suba", 0, AF_STDI,{ 0x80, 0x90, 0xA0, 0x18A0, 0xB0 } }, + { NULL, v_mnemonic, "subb", 0, AF_STDI,{ 0xC0, 0xD0, 0xE0, 0x18E0, 0xF0 } }, + { NULL, v_mnemonic, "subd", 0, AF_STDD,{ 0x83, 0x93, 0xA3, 0x18A3, 0xB3 } }, + { NULL, v_mnemonic, "swi", 0, AF_IMP, { 0x3F } }, + { NULL, v_mnemonic, "tab", 0, AF_IMP, { 0x16 } }, + { NULL, v_mnemonic, "tap", 0, AF_IMP, { 0x06 } }, + { NULL, v_mnemonic, "tba", 0, AF_IMP, { 0x17 } }, + { NULL, v_mnemonic, "test", 0, AF_IMP, { 0x00 } }, + { NULL, v_mnemonic, "tpa", 0, AF_IMP, { 0x07 } }, + { NULL, v_mnemonic, "tsta", 0, AF_IMP, { 0x4D } }, + { NULL, v_mnemonic, "tstb", 0, AF_IMP, { 0x5D } }, + { NULL, v_mnemonic, "tst", 0, AF_ASL, { 0x6D, 0x186D, 0x7D } }, + { NULL, v_mnemonic, "tsx", 0, AF_IMP, { 0x30 } }, + { NULL, v_mnemonic, "tsy", 0, AF_IMP, { 0x1830 } }, + { NULL, v_mnemonic, "txs", 0, AF_IMP, { 0x35 } }, + { NULL, v_mnemonic, "tys", 0, AF_IMP, { 0x1835 } }, + { NULL, v_mnemonic, "wai", 0, AF_IMP, { 0x3E } }, + { NULL, v_mnemonic, "xgdx", 0, AF_IMP, { 0x8F } }, + { NULL, v_mnemonic, "xgdy", 0, AF_IMP, { 0x188F } }, + NULL +}; + + + diff --git a/src/mne68705.c b/src/mne68705.c new file mode 100644 index 00000000..525de343 --- /dev/null +++ b/src/mne68705.c @@ -0,0 +1,123 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + * MNE68705.C + * + * (c)Copyright 1988, Matthew Dillon, All Rights Reserved. + */ + +#include "asm.h" + +#define AFSTD AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_0X + +MNEMONIC Mne68705[] = { + { NULL, v_mnemonic, "adc", 0, AF_IMM8|AFSTD, { 0xA9, 0xB9, 0xE9, 0xC9, 0xD9, 0xF9 } }, + { NULL, v_mnemonic, "add", 0, AF_IMM8|AFSTD, { 0xAB, 0xBB, 0xEB, 0xCB, 0xDB, 0xFB } }, + { NULL, v_mnemonic, "and", 0, AF_IMM8|AFSTD, { 0xA4, 0xB4, 0xE4, 0xC4, 0xD4, 0xF4 } }, + { NULL, v_mnemonic, "asl", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x48, 0x38, 0x68, 0x78 } }, + { NULL, v_mnemonic, "asla", 0,AF_IMP, { 0x48 } }, + { NULL, v_mnemonic, "aslx", 0,AF_IMP, { 0x58 } }, + { NULL, v_mnemonic, "asr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x47, 0x37, 0x67, 0x77 } }, + { NULL, v_mnemonic, "asra", 0,AF_IMP, { 0x47 } }, + { NULL, v_mnemonic, "asrx", 0,AF_IMP, { 0x57 } }, + { NULL, v_mnemonic, "bcc", 0, AF_REL, { 0x24 } }, + { NULL, v_mnemonic, "bclr", MF_IMOD,AF_BITMOD, { 0x11 } }, + { NULL, v_mnemonic, "bcs", 0, AF_REL, { 0x25 } }, + { NULL, v_mnemonic, "beq", 0, AF_REL, { 0x27 } }, + { NULL, v_mnemonic, "bhcc", 0,AF_REL, { 0x28 } }, + { NULL, v_mnemonic, "bhcs", 0,AF_REL, { 0x29 } }, + { NULL, v_mnemonic, "bhi", 0, AF_REL, { 0x22 } }, + { NULL, v_mnemonic, "bhs", 0, AF_REL, { 0x24 } }, + { NULL, v_mnemonic, "bih", 0, AF_REL, { 0x2F } }, + { NULL, v_mnemonic, "bil", 0, AF_REL, { 0x2E } }, + { NULL, v_mnemonic, "bit", 0, AF_IMM8|AFSTD, { 0xA5, 0xB5, 0xE5, 0xC5, 0xD5, 0xF5 } }, + { NULL, v_mnemonic, "blo", 0, AF_REL, { 0x25 } }, + { NULL, v_mnemonic, "bls", 0, AF_REL, { 0x23 } }, + { NULL, v_mnemonic, "bmc", 0, AF_REL, { 0x2C } }, + { NULL, v_mnemonic, "bmi", 0, AF_REL, { 0x2B } }, + { NULL, v_mnemonic, "bms", 0, AF_REL, { 0x2D } }, + { NULL, v_mnemonic, "bne", 0, AF_REL, { 0x26 } }, + { NULL, v_mnemonic, "bpl", 0, AF_REL, { 0x2A } }, + { NULL, v_mnemonic, "bra", 0, AF_REL, { 0x20 } }, + { NULL, v_mnemonic, "brn", 0, AF_REL, { 0x21 } }, + { NULL, v_mnemonic, "brclr", MF_IMOD|MF_REL, AF_BITBRAMOD, { 0x01 } }, + { NULL, v_mnemonic, "brset", MF_IMOD|MF_REL, AF_BITBRAMOD, { 0x00 } }, + { NULL, v_mnemonic, "bset", MF_IMOD,AF_BITMOD, { 0x10 } }, + { NULL, v_mnemonic, "bsr", 0, AF_REL, { 0xAD } }, + { NULL, v_mnemonic, "clc", 0, AF_IMP, { 0x98 } }, + { NULL, v_mnemonic, "cli", 0, AF_IMP, { 0x9A } }, + { NULL, v_mnemonic, "clr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x4F, 0x3F, 0x6F, 0x7F } }, + { NULL, v_mnemonic, "clra", 0,AF_IMP, { 0x4F } }, + { NULL, v_mnemonic, "clrx", 0,AF_IMP, { 0x5F } }, + { NULL, v_mnemonic, "cmp", 0, AF_IMM8|AFSTD, { 0xA1, 0xB1, 0xE1, 0xC1, 0xD1, 0xF1 } }, + { NULL, v_mnemonic, "com", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x43, 0x33, 0x63, 0x73 } }, + { NULL, v_mnemonic, "coma", 0,AF_IMP, { 0x43 } }, + { NULL, v_mnemonic, "comx", 0,AF_IMP, { 0x53 } }, + { NULL, v_mnemonic, "cpx", 0, AF_IMM8|AFSTD, { 0xA3, 0xB3, 0xE3, 0xC3, 0xD3, 0xF3 } }, + { NULL, v_mnemonic, "dec", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x4A, 0x3A, 0x6A, 0x7A } }, + { NULL, v_mnemonic, "deca", 0,AF_IMP, { 0x4A } }, + { NULL, v_mnemonic, "decx", 0,AF_IMP, { 0x5A } }, + { NULL, v_mnemonic, "dex", 0, AF_IMP, { 0x5A } }, + { NULL, v_mnemonic, "eor", 0, AF_IMM8|AFSTD, { 0xA8, 0xB8, 0xE8, 0xC8, 0xD8, 0xF8 } }, + { NULL, v_mnemonic, "inc", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x4C, 0x3C, 0x6C, 0x7C } }, + { NULL, v_mnemonic, "inca", 0,AF_IMP, { 0x4C } }, + { NULL, v_mnemonic, "incx", 0,AF_IMP, { 0x5C } }, + { NULL, v_mnemonic, "inx", 0, AF_IMP, { 0x5C } }, + { NULL, v_mnemonic, "jmp", 0, AFSTD, { 0xBC, 0xEC, 0xCC, 0xDC, 0xFC } }, + { NULL, v_mnemonic, "jsr", 0, AFSTD, { 0xBD, 0xED, 0xCD, 0xDD, 0xFD } }, + { NULL, v_mnemonic, "lda", 0, AF_IMM8|AFSTD, { 0xA6, 0xB6, 0xE6, 0xC6, 0xD6, 0xF6 } }, + { NULL, v_mnemonic, "ldx", 0, AF_IMM8|AFSTD, { 0xAE, 0xBE, 0xEE, 0xCE, 0xDE, 0xFE } }, + { NULL, v_mnemonic, "lsl", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x48, 0x38, 0x68, 0x78 } }, + { NULL, v_mnemonic, "lsla", 0,AF_IMP, { 0x48 } }, + { NULL, v_mnemonic, "lslx", 0,AF_IMP, { 0x58 } }, + { NULL, v_mnemonic, "lsr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x44, 0x34, 0x64, 0x74 } }, + { NULL, v_mnemonic, "lsra", 0,AF_IMP, { 0x44 } }, + { NULL, v_mnemonic, "lsrx", 0,AF_IMP, { 0x54 } }, + { NULL, v_mnemonic, "neg", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x40, 0x30, 0x60, 0x70 } }, + { NULL, v_mnemonic, "nega", 0,AF_IMP, { 0x40 } }, + { NULL, v_mnemonic, "negx", 0,AF_IMP, { 0x50 } }, + { NULL, v_mnemonic, "nop", 0, AF_IMP, { 0x9D } }, + { NULL, v_mnemonic, "ora", 0, AF_IMM8|AFSTD, { 0xAA, 0xBA, 0xEA, 0xCA, 0xDA, 0xFA } }, + { NULL, v_mnemonic, "rol", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x49, 0x39, 0x69, 0x79 } }, + { NULL, v_mnemonic, "rola", 0,AF_IMP, { 0x49 } }, + { NULL, v_mnemonic, "rolx", 0,AF_IMP, { 0x59 } }, + { NULL, v_mnemonic, "ror", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x46, 0x36, 0x66, 0x76 } }, + { NULL, v_mnemonic, "rora", 0,AF_IMP, { 0x46 } }, + { NULL, v_mnemonic, "rorx", 0,AF_IMP, { 0x56 } }, + { NULL, v_mnemonic, "rsp", 0, AF_IMP, { 0x9C } }, + { NULL, v_mnemonic, "rti", 0, AF_IMP, { 0x80 } }, + { NULL, v_mnemonic, "rts", 0, AF_IMP, { 0x81 } }, + { NULL, v_mnemonic, "sbc", 0, AF_IMM8|AFSTD, { 0xA2, 0xB2, 0xE2, 0xC2, 0xD2, 0xF2 } }, + { NULL, v_mnemonic, "sec", 0, AF_IMP, { 0x99 } }, + { NULL, v_mnemonic, "sei", 0, AF_IMP, { 0x9B } }, + { NULL, v_mnemonic, "sta", 0, AFSTD, { 0xB7, 0xE7, 0xC7, 0xD7, 0xF7 } }, + { NULL, v_mnemonic, "stx", 0, AFSTD, { 0xBF, 0xEF, 0xCF, 0xDF, 0xFF } }, + { NULL, v_mnemonic, "sub", 0, AF_IMM8|AFSTD, { 0xA0, 0xB0, 0xE0, 0xC0, 0xD0, 0xF0 } }, + { NULL, v_mnemonic, "swi", 0, AF_IMP, { 0x83 } }, + { NULL, v_mnemonic, "tax", 0, AF_IMP, { 0x97 } }, + { NULL, v_mnemonic, "tst", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X, { 0x4D, 0x3D, 0x6D, 0x7D } }, + { NULL, v_mnemonic, "tsta", 0,AF_IMP, { 0x4D } }, + { NULL, v_mnemonic, "tstx", 0,AF_IMP, { 0x5D } }, + { NULL, v_mnemonic, "txa", 0, AF_IMP, { 0x9F } }, + NULL +}; + diff --git a/src/mnef8.c b/src/mnef8.c new file mode 100644 index 00000000..1a790621 --- /dev/null +++ b/src/mnef8.c @@ -0,0 +1,711 @@ +/* + * MNEMONICF8.C + * + * Fairchild F8 support code for DASM + * 2004 by Thomas Mathys + */ +#include +#include "asm.h" + + +/* + * special registers. must use numbers from 16 and up, + * since numbers below 16 are used for scratchpad registers. + * + * there is no REG_J, since J is really just scratchpad register 9. + */ +enum REGISTERS { + REG_A = 16, + REG_DC0, + REG_H, + REG_IS, + REG_K, + REG_KU, + REG_KL, + REG_PC0, + REG_PC1, + REG_Q, + REG_QU, + REG_QL, + REG_W, + REG_NONE, +}; + + +/* + * used to print error messages. + * mnename and opstring are copied into a single error message, + * which is passed to asmerr. + * + * err : error code (ERROR_xxx constant, passed to asmerr) + * mnename : name of the mnemonic + * opstring : operand string + * abort : false = don't abort assembly + * true = abort assembly + */ +static void f8err(int err, char *mnename, char *opstring, bool abort) { + + char *buf; + + buf = ckmalloc(strlen(mnename) + strlen(opstring) + 64); + strcpy(buf, mnename); + strcat(buf, " "); + strcat(buf, opstring); + asmerr(err, abort, buf); + free(buf); +} + + +/* + * emits a one byte opcode. + */ +static void emit_opcode1(unsigned char opcode) { + Glen = 1; + Gen[0] = opcode; + generate(); +} + + +/* + * emits a two byte opcode + * + * byte0 : first byte (lower address) + * byte1 : second byte (higher address) + */ +static void emit_opcode2(unsigned char byte0, unsigned char byte1) { + Glen = 2; + Gen[0] = byte0; + Gen[1] = byte1; + generate(); +} + + +/* + * emits a three byte opcode + * + * byte0 : first byte (lowest address) + * byte1 : second byte (middle address) + * byte2 : third byte (highest address) + */ +static void emit_opcode3(unsigned char byte0, unsigned char byte1, unsigned char byte2) { + Glen = 3; + Gen[0] = byte0; + Gen[1] = byte1; + Gen[2] = byte2; + generate(); +} + + + +/* + * check wether the current program counter is known. + * + * result : zero = current program counter is unknown + * nonzero = current program counter is known + */ +int isPCKnown(void) { + unsigned char pcf; + pcf= (Csegment->flags & SF_RORG) ? Csegment->rflags : Csegment->flags; + return ((pcf & (SF_UNKNOWN|2)) == 0) ? 1 : 0; +} + + +/* + * returns the current program counter + */ +static long getPC(void) { + return (Csegment->flags & SF_RORG) ? Csegment->rorg : Csegment->org; +} + + +/* + * attempts to parse a 32 bit unsigned value from a string. + * + * str : string to parse the value from + * value : parsed value is stored here + * + * result : zero = ok or syntax error + * nonzero = unresolved expression + */ +static int parse_value(char *str, unsigned long *value) { + + SYMBOL *sym; + int result = 0; + + *value = 0; + sym = eval(str, 0); + + if (NULL != sym->next || AM_BYTEADR != sym->addrmode) { + asmerr(ERROR_SYNTAX_ERROR, true, str); + } + else if (sym->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_MNEMONIC_NOT_RESOLVED; + result = 1; + } + else { + *value = sym->value; + } + FreeSymbolList(sym); + + return result; +} + + +/* + * attempts to parse a scratchpad register name. + * register numbers are parsed as expressions. + * if an expression is invalid, asmerr is called + * and the assembly aborted. + * + * accepts the following input: + * + * - numbers 0..14 (as expressions, numbers 12-14 map to S, I and D) + * - J (alias for register 9) + * - HU (alias for register 10) + * - HL (alias for register 11) + * - S and (IS) + * - I and (IS)+ + * - D and (IS)- + * + * str : string to parse the scratchpad register from + * reg : parsed scratchpad register is stored here. + * this is the value which will become the lower + * nibble of the opcodes. + * + * result : zero = ok or syntax error + * nonzero = unresolved expression + */ +static int parse_scratchpad_register(char *str, unsigned char *reg) { + + unsigned long regnum; + + /* parse special cases where ISAR is used as index */ + if (!stricmp("s", str) || !stricmp("(is)", str)) { + *reg = 0x0c; + return 0; + } + if (!stricmp("i", str) || !stricmp("(is)+", str)) { + *reg = 0x0d; + return 0; + } + if (!stricmp("d", str) || !stricmp("(is)-", str)) { + *reg = 0x0e; + return 0; + } + + /* parse aliases for scratchpad registers */ + if (!stricmp("j", str)) { + *reg = 0x09; + return 0; + } + if (!stricmp("hu", str)) { + *reg = 0x0a; + return 0; + } + if (!stricmp("hl", str)) { + *reg = 0x0b; + return 0; + } + + /* parse register number */ + if (parse_value(str, ®num)) { + return 1; /* unresolved expr */ + } else { + if (regnum > 14) { + asmerr(ERROR_VALUE_MUST_BE_LT_F, true, str); + } + *reg = regnum; + return 0; + } +} + + +/* + * attempts to parse a special register name from str + * + * result : one of the REG_xxx constants (possibly also REG_NONE) + */ +static int parse_special_register(char *str) { + + if (!stricmp("a", str)) { + return REG_A; + } + if (!stricmp("dc0", str) || !stricmp("dc", str) ) { + return REG_DC0; + } + if (!stricmp("h", str)) { + return REG_H; + } + if (!stricmp("is", str)) { + return REG_IS; + } + if (!stricmp("k", str)) { + return REG_K; + } + if (!stricmp("ku", str)) { + return REG_KU; + } + if (!stricmp("kl", str)) { + return REG_KL; + } + if (!stricmp("pc0", str) || !stricmp("p0", str)) { + return REG_PC0; + } + if (!stricmp("pc1", str) || !stricmp("p", str)) { + return REG_PC1; + } + if (!stricmp("q", str)) { + return REG_Q; + } + if (!stricmp("qu", str)) { + return REG_QU; + } + if (!stricmp("ql", str)) { + return REG_QL; + } + if (!stricmp("w", str)) { + return REG_W; + } + else { + return REG_NONE; + } +} + + +static void v_ins_outs(char *str, MNEMONIC *mne) { + + unsigned long operand; + + programlabel(); + parse_value(str, &operand); + if (operand > 15) { + f8err(ERROR_VALUE_MUST_BE_LT_10, mne->name, str, false); + } + emit_opcode1(mne->opcode[0] | (operand & 15)); +} + + +static void v_sl_sr(char *str, MNEMONIC *mne) { + + unsigned long operand; + + programlabel(); + + if (parse_value(str, &operand)) { + /* unresolved expression, reserve space */ + emit_opcode1(0); + } else { + switch (operand) { + case 1: + emit_opcode1(mne->opcode[0]); + break; + case 4: + emit_opcode1(mne->opcode[0] + 2); + break; + default: + f8err(ERROR_VALUE_MUST_BE_1_OR_4, mne->name, str, false); + emit_opcode1(0); + break; + } + } +} + + +static void v_lis(char *str, MNEMONIC *mne) { + + unsigned long operand; + + programlabel(); + parse_value(str, &operand); + if (operand > 15) { + f8err(ERROR_VALUE_MUST_BE_LT_10, mne->name, str, false); + } + emit_opcode1(0x70 | (operand & 15)); +} + + +static void v_lisu_lisl(char *str, MNEMONIC *mne) { + + unsigned long operand; + + programlabel(); + parse_value(str, &operand); + if (operand > 7) { + f8err(ERROR_VALUE_MUST_BE_LT_8, mne->name, str, false); + } + emit_opcode1(mne->opcode[0] | (operand & 7)); +} + + +/* + * handles opcodes with a scratchpad register operand: + * as, asd, ds, ns, xs + */ +static void v_sreg_op(char *str, MNEMONIC *mne) { + + unsigned char reg; + + programlabel(); + parse_scratchpad_register(str, ®); + emit_opcode1(mne->opcode[0] | reg); +} + + +static void v_lr(char *str, MNEMONIC *mne) { + + int i; + int ncommas; + int cindex; + char *op1; + char *op2; + unsigned char reg_dst; + unsigned char reg_src; + int opcode; + + programlabel(); + + /* a valid operand string must contain exactly one comma. find it. */ + ncommas = 0; + cindex = 0; + for (i=0; str[i]; i++) { + if (',' == str[i]) { + ncommas++; + cindex = i; + } + } + if (1 != ncommas) { + f8err(ERROR_SYNTAX_ERROR, mne->name, str, false); + return; + } + + /* extract operand strings */ + str[cindex] = 0; + op1 = str; + op2 = &str[cindex+1]; + if ( (0 != cindex) && (isspace(str[cindex-1])) ) { + str[cindex-1] = 0; + } + if (isspace(*op2)) { + op2++; + } + + /* parse operand strings for register names */ + reg_dst = parse_special_register(op1); + if (REG_NONE == reg_dst) { + if (parse_scratchpad_register(op1, ®_dst)) { + /* unresolved expression, reserve space */ + emit_opcode1(0); + return; + } + } + reg_src = parse_special_register(op2); + if (REG_NONE == reg_src) { + if (parse_scratchpad_register(op2, ®_src)) { + /* unresolved expression, reserve space */ + emit_opcode1(0); + return; + } + } + + /* restore operand string */ + str[cindex] = ','; + if ( (0 != cindex) && (0 == str[cindex-1])) { + str[cindex-1] = ' '; + } + + /* generate opcode */ + opcode = -1; + switch (reg_dst) { + case REG_A: /* lr a,xxx */ + switch (reg_src) { + case REG_IS: opcode = 0x0a; break; + case REG_KL: opcode = 0x01; break; + case REG_KU: opcode = 0x00; break; + case REG_QL: opcode = 0x03; break; + case REG_QU: opcode = 0x02; break; + default: + if (reg_src < 15) { + opcode = 0x40 | reg_src; + } + break; + } + break; + case REG_DC0: + switch (reg_src) { + case REG_H: opcode = 0x10; break; + case REG_Q: opcode = 0x0f; break; + } + break; + case REG_H: + if (REG_DC0 == reg_src) opcode = 0x11; + break; + case REG_IS: + if (REG_A == reg_src) opcode = 0x0b; + break; + case REG_K: + if (REG_PC1 == reg_src) opcode = 0x08; + break; + case REG_KL: + if (REG_A == reg_src) opcode = 0x05; + break; + case REG_KU: + if (REG_A == reg_src) opcode = 0x04; + break; + case REG_PC0: + if (REG_Q == reg_src) opcode = 0x0d; + break; + case REG_PC1: + if (REG_K == reg_src) opcode = 0x09; + break; + case REG_Q: + if (REG_DC0 == reg_src) opcode = 0x0e; + break; + case REG_QL: + if (REG_A == reg_src) opcode = 0x07; + break; + case REG_QU: + if (REG_A == reg_src) opcode = 0x06; + break; + case REG_W: + if (0x09 == reg_src) opcode = 0x1d; + break; + default: /* lr sreg,xxx*/ + if ( (15 > reg_dst) && (REG_A == reg_src) ) { + /* lr sreg,a */ + opcode = 0x50 | reg_dst; + } + else if ( (9 == reg_dst) && (REG_W == reg_src) ) { + /* special case : lr j,w */ + opcode = 0x1e; + } + break; + } + if (opcode < 0) { + f8err(ERROR_ILLEGAL_OPERAND_COMBINATION, mne->name, str, true); + } else { + emit_opcode1(opcode); + } +} + + +/* + * generates branch opcodes + * + * opcode : opcode of the branch (for instance 0x8f for BR7) + * str : operand string + */ +static void generate_branch(unsigned char opcode, char *str) { + + unsigned long target_adr; + long disp; + + programlabel(); + + /* get target address */ + if (parse_value(str, &target_adr)) { + /* unresolved target address, reserve space */ + emit_opcode2(0, 0); + return; + } + + /* calculate displacement */ + if (isPCKnown()) { + disp = target_adr - getPC() - 1; + if (disp > 127 || disp < -128) { + char buf[64]; + sprintf(buf, "%d", (int)disp); + asmerr(ERROR_BRANCH_OUT_OF_RANGE, false, buf); + } + } else { + /* unknown pc, will be (hopefully) resolved in future passes */ + disp = 0; + } + + emit_opcode2(opcode, disp & 255); +} + + +/* + * handles the following branch mnemonics: + * bc, bm, bnc, bno, bnz, bp, br, br7, bz + */ +static void v_branch(char *str, MNEMONIC *mne) { + generate_branch(mne->opcode[0], str); +} + + +static void v_bf_bt(char *str, MNEMONIC *mne) { + + int ncommas; + int cindex; + int i; + char *op1; + char *op2; + unsigned long value; + + /* a valid operand string must contain exactly one comma. find it. */ + ncommas = 0; + cindex = 0; + for (i=0; str[i]; i++) { + if (',' == str[i]) { + ncommas++; + cindex = i; + } + } + if (1 != ncommas) { + f8err(ERROR_SYNTAX_ERROR, mne->name, str, false); + return; + } + + /* extract operands */ + str[cindex] = 0; + op1 = str; + op2 = &str[cindex+1]; + + /* parse first operand*/ + if (parse_value(op1, &value)) { + /* unresolved expression, reserve space */ + emit_opcode2(0, 0); + return; + } + + /* check first operand */ + str[cindex] = ','; /* restore operand string */ + if ('f' == mne->name[1]) { + /* bf */ + if (value > 15) { + f8err(ERROR_VALUE_MUST_BE_LT_10, mne->name, str, false); + value &= 15; + } + } else { + /* bt */ + if (value > 7) { + f8err(ERROR_VALUE_MUST_BE_LT_8, mne->name, str, false); + value &= 7; + } + } + + generate_branch(mne->opcode[0] | value, op2); +} + + +/* + * handles instructions that take a word operand: + * dci, jmp, pi + */ +static void v_wordop(char *str, MNEMONIC *mne) { + + unsigned long value; + + programlabel(); + parse_value(str, &value); + if (value > 0xffff) { + f8err(ERROR_VALUE_MUST_BE_LT_10000, mne->name, str, false); + } + emit_opcode3(mne->opcode[0], (value >> 8) & 0xff, value & 0xff); +} + + +/* + * handles instructions that take a byte operand: + * ai, ci, in, li, ni, oi, out, xi + */ +static void v_byteop(char *str, MNEMONIC *mne) { + + unsigned long value; + + programlabel(); + parse_value(str, &value); + if (value > 0xff) { + f8err(ERROR_ADDRESS_MUST_BE_LT_100, mne->name, str, false); + } + emit_opcode2(mne->opcode[0], value & 0xff); +} + + +MNEMONIC MneF8[] = { + + /* ds is an f8 opcode, so we replace the ds directive by res */ + {NULL, v_ds, "res", 0, 0}, + + /* add db/dw/dd directives for f8tool compatibility */ + {NULL, v_dc, "db", 0, 0}, + {NULL, v_dc, "dw", 0, 0}, + {NULL, v_dc, "dd", 0, 0}, + + /* + * f8 opcodes + * + * some instructions have AF_IMP in der addressflag, although + * they are handled by own handlers and have explicit operands. + * this is to keep dasm from clearing the opcode array when + * adding the hashtable. + * + * the only instructions that are handled by v_mnemonic are + * those with implicit operands. + * + * other f8 instructions have register operands, which v_mnemonic + * can't handle. + * + * or they have byte and word operands (values or addresses). + * these could theoretically be handled by v_mnemonic, but + * we do it ourselves anyway, since this allows us to have + * expressions with parentheses as operands. + */ + {NULL, v_mnemonic, "adc", 0, AF_IMP, {0x8e}}, + {NULL, v_byteop, "ai" , 0, AF_IMP, {0x24}}, + {NULL, v_mnemonic, "am" , 0, AF_IMP, {0x88}}, + {NULL, v_mnemonic, "amd", 0, AF_IMP, {0x89}}, + {NULL, v_sreg_op, "as" , 0, AF_IMP, {0xc0}}, /* base opcode */ + {NULL, v_sreg_op, "asd", 0, AF_IMP, {0xd0}}, /* base opcode */ + {NULL, v_branch, "bc" , 0, AF_IMP, {0x82}}, + {NULL, v_bf_bt, "bf" , 0, AF_IMP, {0x90}}, /* base opcode */ + {NULL, v_branch, "bm" , 0, AF_IMP, {0x91}}, + {NULL, v_branch, "bnc", 0, AF_IMP, {0x92}}, + {NULL, v_branch, "bno", 0, AF_IMP, {0x98}}, + {NULL, v_branch, "bnz", 0, AF_IMP, {0x94}}, + {NULL, v_branch, "bp" , 0, AF_IMP, {0x81}}, + {NULL, v_branch, "br" , 0, AF_IMP, {0x90}}, + {NULL, v_branch, "br7", 0, AF_IMP, {0x8f}}, + {NULL, v_bf_bt, "bt" , 0, AF_IMP, {0x80}}, /* base opcode */ + {NULL, v_branch, "bz" , 0, AF_IMP, {0x84}}, + {NULL, v_byteop, "ci" , 0, AF_IMP, {0x25}}, + {NULL, v_mnemonic, "clr", 0, AF_IMP, {0x70}}, + {NULL, v_mnemonic, "cm" , 0, AF_IMP, {0x8d}}, + {NULL, v_mnemonic, "com", 0, AF_IMP, {0x18}}, + {NULL, v_wordop, "dci", 0, AF_IMP, {0x2a}}, + {NULL, v_mnemonic, "di" , 0, AF_IMP, {0x1a}}, + {NULL, v_sreg_op, "ds" , 0, AF_IMP, {0x30}}, /* base opcode */ + {NULL, v_mnemonic, "ei" , 0, AF_IMP, {0x1b}}, + {NULL, v_byteop, "in" , 0, AF_IMP, {0x26}}, + {NULL, v_mnemonic, "inc", 0, AF_IMP, {0x1f}}, + {NULL, v_ins_outs, "ins", 0, AF_IMP, {0xa0}}, /* base opcode */ + {NULL, v_wordop, "jmp", 0, AF_IMP, {0x29}}, + {NULL, v_byteop, "li" , 0, AF_IMP, {0x20}}, + {NULL, v_lis, "lis", 0, 0}, + {NULL, v_lisu_lisl,"lisl",0, AF_IMP, {0x68}}, /* base opcode */ + {NULL, v_lisu_lisl,"lisu",0, AF_IMP, {0x60}}, /* base opcode */ + {NULL, v_mnemonic, "lm" , 0, AF_IMP, {0x16}}, + {NULL, v_mnemonic, "lnk", 0, AF_IMP, {0x19}}, + {NULL, v_lr, "lr" , 0, 0}, + {NULL, v_byteop, "ni" , 0, AF_IMP, {0x21}}, + {NULL, v_mnemonic, "nm" , 0, AF_IMP, {0x8a}}, + {NULL, v_mnemonic, "nop", 0, AF_IMP, {0x2b}}, + {NULL, v_sreg_op, "ns" , 0, AF_IMP, {0xf0}}, /* base opcode */ + {NULL, v_byteop, "oi" , 0, AF_IMP, {0x22}}, + {NULL, v_mnemonic, "om" , 0, AF_IMP, {0x8b}}, + {NULL, v_byteop, "out", 0, AF_IMP, {0x27}}, + {NULL, v_ins_outs, "outs",0, AF_IMP, {0xb0}}, /* base opcode */ + {NULL, v_wordop, "pi" , 0, AF_IMP, {0x28}}, + {NULL, v_mnemonic, "pk" , 0, AF_IMP, {0x0c}}, + {NULL, v_mnemonic, "pop", 0, AF_IMP, {0x1c}}, + {NULL, v_sl_sr, "sl" , 0, AF_IMP, {0x13}}, /* base opcode for "sl 1" */ + {NULL, v_sl_sr, "sr" , 0, AF_IMP, {0x12}}, /* base opcode for "sr 1" */ + {NULL, v_mnemonic, "st" , 0, AF_IMP, {0x17}}, + {NULL, v_mnemonic, "xdc", 0, AF_IMP, {0x2c}}, + {NULL, v_byteop, "xi" , 0, AF_IMP, {0x23}}, + {NULL, v_mnemonic, "xm" , 0, AF_IMP, {0x8c}}, + {NULL, v_sreg_op, "xs" , 0, AF_IMP, {0xe0}}, /* base opcode */ + NULL +}; diff --git a/src/ops.c b/src/ops.c new file mode 100644 index 00000000..ce3dc4b3 --- /dev/null +++ b/src/ops.c @@ -0,0 +1,1483 @@ +/* + DASM Assembler + Portions of this code are Copyright (C)1988 Matthew Dillon + and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* +* OPS.C +* +* (c)Copyright 1988, Matthew Dillon, All Rights Reserved. +* +* Handle mnemonics and pseudo ops +* +*/ + +#include "asm.h" + +unsigned char Gen[256]; +unsigned char OrgFill = DEFORGFILL; +int Glen; + +extern MNEMONIC Mne6502[]; +extern MNEMONIC Mne6803[]; +extern MNEMONIC MneHD6303[]; +extern MNEMONIC Mne68705[]; +extern MNEMONIC Mne68HC11[]; +extern MNEMONIC MneF8[]; + +void generate(void); +void genfill(long fill, long bytes, int size); +void pushif(bool xbool); +int gethexdig(int c); + +/* +* An opcode modifies the SEGMENT flags in the following ways: +*/ + +void v_processor(char *str, MNEMONIC *dummy) +{ + static bool bCalled = false; + unsigned long PreviousProcessor = Processor; + + Processor = 0; + + if (strcmp(str,"6502") == 0) + { + if ( !bCalled ) + addhashtable(Mne6502); + + MsbOrder = 0; /* lsb,msb */ + Processor = 6502; + } + + if (strcmp(str,"6803") == 0) + { + if ( !bCalled ) + addhashtable(Mne6803); + + MsbOrder = 1; /* msb,lsb */ + Processor = 6803; + } + + if (strcmp(str,"HD6303") == 0 || strcmp(str, "hd6303") == 0) + { + if ( !bCalled ) + { + addhashtable(Mne6803); + addhashtable(MneHD6303); + } + + MsbOrder = 1; /* msb,lsb */ + Processor = 6303; + } + + if (strcmp(str,"68705") == 0) + { + if ( !bCalled ) + addhashtable(Mne68705); + + MsbOrder = 1; /* msb,lsb */ + Processor = 68705; + } + + if (strcmp(str,"68HC11") == 0 || strcmp(str, "68hc11") == 0) + { + if ( !bCalled ) + addhashtable(Mne68HC11); + + MsbOrder = 1; /* msb,lsb */ + Processor = 6811; + } + + if (strcmp(str,"F8") == 0 || strcmp(str, "f8") == 0) + { + if ( !bCalled ) + addhashtable(MneF8); + + MsbOrder = 1; + Processor = 0xf8; + } + + bCalled = true; + + if ( !Processor ) + { + asmerr( ERROR_PROCESSOR_NOT_SUPPORTED, true, str ); + } + + if ( PreviousProcessor && Processor != PreviousProcessor ) + { + asmerr( ERROR_ONLY_ONE_PROCESSOR_SUPPORTED, true, str ); + } + +} + +#define badcode(mne,adrmode) (!(mne->okmask & (1L << adrmode))) + +void v_mnemonic(char *str, MNEMONIC *mne) +{ + int addrmode; + SYMBOL *sym; + unsigned int opcode; + short opidx; + SYMBOL *symbase; + int opsize; + + Csegment->flags |= SF_REF; + programlabel(); + symbase = eval(str, 1); + + if ( bTrace ) + printf("PC: %04lx MNEMONIC: %s addrmode: %d ", Csegment->org, mne->name, symbase->addrmode); + + for (sym = symbase; sym; sym = sym->next) + { + if (sym->flags & SYM_UNKNOWN) + { + ++Redo; + Redo_why |= REASON_MNEMONIC_NOT_RESOLVED; + } + } + sym = symbase; + + if (mne->flags & MF_IMOD) + { + if (sym->next) + { + sym->addrmode = AM_BITMOD; + if ((mne->flags & MF_REL) && sym->next) + sym->addrmode = AM_BITBRAMOD; + } + } + addrmode = sym->addrmode; + if ((sym->flags & SYM_UNKNOWN) || sym->value >= 0x100) + opsize = 2; + else + opsize = (sym->value) ? 1 : 0; + + while (badcode(mne,addrmode) && Cvt[addrmode]) + addrmode = Cvt[addrmode]; + + if ( bTrace ) + printf("mnemask: %08lx adrmode: %d Cvt[am]: %d\n", mne->okmask, addrmode, Cvt[addrmode]); + + if (badcode(mne,addrmode)) + { + char sBuffer[128]; + sprintf( sBuffer, "%s %s", mne->name, str ); + asmerr( ERROR_ILLEGAL_ADDRESSING_MODE, false, sBuffer ); + FreeSymbolList(symbase); + return; + } + + if (Mnext >= 0 && Mnext < NUMOC) /* Force */ + { + addrmode = Mnext; + + if (badcode(mne,addrmode)) + { + asmerr( ERROR_ILLEGAL_FORCED_ADDRESSING_MODE, false, mne->name ); + FreeSymbolList(symbase); + return; + } + } + + if ( bTrace ) + printf("final addrmode = %d\n", addrmode); + + while (opsize > Opsize[addrmode]) + { + if (Cvt[addrmode] == 0 || badcode(mne,Cvt[addrmode])) + { + char sBuffer[128]; + + if (sym->flags & SYM_UNKNOWN) + break; + + sprintf( sBuffer, "%s %s", mne->name, str ); + asmerr( ERROR_ADDRESS_MUST_BE_LT_100, false, sBuffer ); + break; + } + addrmode = Cvt[addrmode]; + } + opcode = mne->opcode[addrmode]; + opidx = 1 + (opcode > 0xFF); + if (opidx == 2) + { + Gen[0] = opcode >> 8; + Gen[1] = opcode; + } + else + { + Gen[0] = opcode; + } + + switch(addrmode) + { + case AM_BITMOD: + sym = symbase->next; + if (!(sym->flags & SYM_UNKNOWN) && sym->value >= 0x100) + asmerr( ERROR_ADDRESS_MUST_BE_LT_100, false, NULL ); + Gen[opidx++] = sym->value; + + if (!(symbase->flags & SYM_UNKNOWN)) + { + if (symbase->value > 7) + asmerr( ERROR_ILLEGAL_BIT_SPECIFICATION, false, str ); + else + Gen[0] += symbase->value << 1; + } + break; + + case AM_BITBRAMOD: + + if (!(symbase->flags & SYM_UNKNOWN)) + { + if (symbase->value > 7) + asmerr( ERROR_ILLEGAL_BIT_SPECIFICATION, false, str ); + else + Gen[0] += symbase->value << 1; + } + + sym = symbase->next; + + if (!(sym->flags & SYM_UNKNOWN) && sym->value >= 0x100) + asmerr( ERROR_ADDRESS_MUST_BE_LT_100, false, NULL ); + + Gen[opidx++] = sym->value; + sym = sym->next; + break; + + case AM_REL: + break; + + default: + if (Opsize[addrmode] > 0) + Gen[opidx++] = sym->value; + if (Opsize[addrmode] == 2) + { + if (MsbOrder) + { + Gen[opidx-1] = sym->value >> 8; + Gen[opidx++] = sym->value; + } + else + { + Gen[opidx++] = sym->value >> 8; + } + } + sym = sym->next; + break; + } + + if (mne->flags & MF_MASK) + { + if (sym) + { + if (!(sym->flags & SYM_UNKNOWN) && sym->value >= 0x100) + asmerr( ERROR_ADDRESS_MUST_BE_LT_100, false, NULL ); + + Gen[opidx] = sym->value; + sym = sym->next; + } + else + { + asmerr( ERROR_NOT_ENOUGH_ARGS, true, NULL ); + } + + ++opidx; + } + + if ((mne->flags & MF_REL) || addrmode == AM_REL) + { + ++opidx; /* to end of instruction */ + + if (!sym) + asmerr( ERROR_NOT_ENOUGH_ARGS, true, NULL ); + else if (!(sym->flags & SYM_UNKNOWN)) + { + long pc; + unsigned char pcf; + long dest; + + pc = (Csegment->flags & SF_RORG) ? Csegment->rorg : Csegment->org; + pcf= (Csegment->flags & SF_RORG) ? Csegment->rflags : Csegment->flags; + + if ((pcf & (SF_UNKNOWN|2)) == 0) + { + dest = sym->value - pc - opidx; + if (dest >= 128 || dest < -128) + { + char sBuffer[64]; + sprintf( sBuffer, "%d", dest ); + asmerr( ERROR_BRANCH_OUT_OF_RANGE, false, sBuffer ); + + } + } + else + { + /* Don't bother - we'll take another pass */ + dest = 0; + } + Gen[opidx-1] = dest & 0xFF; /* byte before end of inst. */ + } + } + Glen = opidx; + generate(); + FreeSymbolList(symbase); +} + +void v_trace(char *str, MNEMONIC *dummy) +{ + bTrace = (str[1] == 'n'); +} + +void v_list(char *str, MNEMONIC *dummy) +{ + programlabel(); + + Glen = 0; /* Only so outlist() works */ + + if (strncmp(str, "localoff", 7) == 0 || strncmp(str, "LOCALOFF", 7) == 0) + pIncfile->flags |= INF_NOLIST; + else if (strncmp(str, "localon", 7) == 0 || strncmp(str, "LOCALON", 7) == 0) + pIncfile->flags &= ~INF_NOLIST; + else if (strncmp(str, "off", 2) == 0 || strncmp(str, "OFF", 2) == 0) + ListMode = 0; + else + ListMode = 1; +} + +char * +getfilename(char *str) +{ + if (*str == '\"') { + char *buf; + + str++; + buf = ckmalloc(strlen(str)+1); + strcpy(buf, str); + + for (str = buf; *str && *str != '\"'; ++str); + *str = 0; + + return buf; + } + return str; +} + +void +v_include(char *str, MNEMONIC *dummy) +{ + char *buf; + + programlabel(); + buf = getfilename(str); + + pushinclude(buf); + + if (buf != str) + free(buf); +} + + +void +v_incbin(char *str, MNEMONIC *dummy) +{ + char *buf; + FILE *binfile; + + programlabel(); + buf = getfilename(str); + + binfile = pfopen(buf, "rb"); + if (binfile) { + if (Redo) { + /* optimize: don't actually read the file if not needed */ + fseek(binfile, 0, SEEK_END); + Glen = ftell(binfile); + generate(); /* does not access Gen[] if Redo is set */ + } + else + { + for (;;) { + Glen = fread(Gen, 1, sizeof(Gen), binfile); + if (Glen <= 0) + break; + generate(); + } + } + fclose(binfile); + } + else + { + printf("unable to open %s\n", buf); + } + + if (buf != str) + free(buf); + Glen = 0; /* don't list hexdump */ +} + + + +void +v_seg(char *str, MNEMONIC *dummy) +{ + SEGMENT *seg; + + for (seg = Seglist; seg; seg = seg->next) { + if (strcmp(str, seg->name) == 0) { + Csegment = seg; + programlabel(); + return; + } + } + Csegment = seg = (SEGMENT *)zmalloc(sizeof(SEGMENT)); + seg->next = Seglist; + seg->name = strcpy(ckmalloc(strlen(str)+1), str); + seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN; + Seglist = seg; + if (Mnext == AM_BSS) + seg->flags |= SF_BSS; + programlabel(); +} + +void +v_hex(char *str, MNEMONIC *dummy) +{ + int i; + int result; + + programlabel(); + Glen = 0; + for (i = 0; str[i]; ++i) { + if (str[i] == ' ') + continue; + result = (gethexdig(str[i]) << 4) + gethexdig(str[i+1]); + if (str[++i] == 0) + break; + Gen[Glen++] = result; + } + generate(); +} + +int +gethexdig(int c) +{ + char sBuffer[64]; + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + sprintf( sBuffer, "Bad Hex Digit %c", c ); + asmerr( ERROR_SYNTAX_ERROR, false, sBuffer ); + + puts("(Must be a valid hex digit)"); + if (F_listfile) + fputs("(Must be a valid hex digit)\n", FI_listfile); + + return 0; +} + +void +v_err(char *str, MNEMONIC *dummy) +{ + programlabel(); + asmerr( ERROR_ERR_PSEUDO_OP_ENCOUNTERED, true, NULL ); + exit(1); +} + +void +v_dc(char *str, MNEMONIC *mne) +{ + SYMBOL *sym; + SYMBOL *tmp; + unsigned long value; + char *macstr = 0; /* "might be used uninitialised" */ + char vmode = 0; + + Glen = 0; + programlabel(); + + + /* for byte, .byte, word, .word, long, .long */ + if (mne->name[0] != 'd') { + static char tmp[4]; + strcpy(tmp, "x.x"); + tmp[2] = mne->name[0]; + findext(tmp); + } + + /* F8... */ + + /* db, dw, dd */ + if ( (mne->name[0] == 'd') && (mne->name[1] != 'c') ) { + static char tmp[4]; + strcpy(tmp, "x.x"); + if ('d' == mne->name[1]) { + tmp[2] = 'l'; + } else { + tmp[2] = mne->name[1]; + } + findext(tmp); + } + + /* ...F8 */ + + + + if (mne->name[1] == 'v') { + int i; + vmode = 1; + for (i = 0; str[i] && str[i] != ' '; ++i); + tmp = findsymbol(str, i); + str += i; + if (tmp == NULL) { + puts("EQM label not found"); + return; + } + if (tmp->flags & SYM_MACRO) { + macstr = (void *)tmp->string; + } + else + { + puts("must specify EQM label for DV"); + return; + } + } + sym = eval(str, 0); + for (; sym; sym = sym->next) { + value = sym->value; + if (sym->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_DC_NOT_RESOVED; + } + if (sym->flags & SYM_STRING) { + unsigned char *ptr = (void *)sym->string; + while ((value = *ptr) != 0) { + if (vmode) { + setspecial(value, 0); + tmp = eval(macstr, 0); + value = tmp->value; + if (tmp->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_DV_NOT_RESOLVED_PROBABLY; + } + FreeSymbolList(tmp); + } + switch(Mnext) { + default: + case AM_BYTE: + Gen[Glen++] = value & 0xFF; + break; + case AM_WORD: + if (MsbOrder) { + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = value & 0xFF; + } + else + { + Gen[Glen++] = value & 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + } + break; + case AM_LONG: + if (MsbOrder) { + Gen[Glen++] = (value >> 24)& 0xFF; + Gen[Glen++] = (value >> 16)& 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = value & 0xFF; + } + else + { + Gen[Glen++] = value & 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = (value >> 16)& 0xFF; + Gen[Glen++] = (value >> 24)& 0xFF; + } + break; + } + ++ptr; + } + } + else + { + if (vmode) { + setspecial(value, sym->flags); + tmp = eval(macstr, 0); + value = tmp->value; + if (tmp->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_DV_NOT_RESOLVED_COULD; + } + FreeSymbolList(tmp); + } + switch(Mnext) { + default: + case AM_BYTE: + Gen[Glen++] = value & 0xFF; + break; + case AM_WORD: + if (MsbOrder) { + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = value & 0xFF; + } + else + { + Gen[Glen++] = value & 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + } + break; + case AM_LONG: + if (MsbOrder) { + Gen[Glen++] = (value >> 24)& 0xFF; + Gen[Glen++] = (value >> 16)& 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = value & 0xFF; + } + else + { + Gen[Glen++] = value & 0xFF; + Gen[Glen++] = (value >> 8) & 0xFF; + Gen[Glen++] = (value >> 16)& 0xFF; + Gen[Glen++] = (value >> 24)& 0xFF; + } + break; + } + } + } + generate(); + FreeSymbolList(sym); +} + + + +void +v_ds(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym; + int mult = 1; + long filler = 0; + + if (Mnext == AM_WORD) + mult = 2; + if (Mnext == AM_LONG) + mult = 4; + programlabel(); + if ((sym = eval(str, 0)) != NULL) { + if (sym->next) + filler = sym->next->value; + if (sym->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_DS_NOT_RESOLVED; + } + else + { + if (sym->next && sym->next->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_DS_NOT_RESOLVED; + } + genfill(filler, sym->value, mult); + } + FreeSymbolList(sym); + } +} + +void +v_org(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym; + + sym = eval(str, 0); + Csegment->org = sym->value; + + if (sym->flags & SYM_UNKNOWN) + Csegment->flags |= SYM_UNKNOWN; + else + Csegment->flags &= ~SYM_UNKNOWN; + + if (Csegment->initflags & SYM_UNKNOWN) + { + Csegment->initorg = sym->value; + Csegment->initflags = sym->flags; + } + + if (sym->next) + { + OrgFill = sym->next->value; + if (sym->next->flags & SYM_UNKNOWN) + asmerr( ERROR_VALUE_UNDEFINED, true, NULL ); + } + + programlabel(); + FreeSymbolList(sym); +} + +void +v_rorg(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym = eval(str, 0); + + Csegment->flags |= SF_RORG; + if (sym->addrmode != AM_IMP) { + Csegment->rorg = sym->value; + if (sym->flags & SYM_UNKNOWN) + Csegment->rflags |= SYM_UNKNOWN; + else + Csegment->rflags &= ~SYM_UNKNOWN; + if (Csegment->initrflags & SYM_UNKNOWN) { + Csegment->initrorg = sym->value; + Csegment->initrflags = sym->flags; + } + } + programlabel(); + FreeSymbolList(sym); +} + +void +v_rend(char *str, MNEMONIC *dummy) +{ + programlabel(); + Csegment->flags &= ~SF_RORG; +} + +void +v_align(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym = eval(str, 0); + unsigned char fill = 0; + unsigned char rorg = Csegment->flags & SF_RORG; + + if (rorg) + Csegment->rflags |= SF_REF; + else + Csegment->flags |= SF_REF; + if (sym->next) { + if (sym->next->flags & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_ALIGN_NOT_RESOLVED; + } + else + { + fill = sym->value; + } + } + if (rorg) { + if ((Csegment->rflags | sym->flags) & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_ALIGN_RELOCATABLE_ORIGIN_NOT_KNOWN; + } + else + { + long n = sym->value - (Csegment->rorg % sym->value); + if (n != sym->value) + genfill(fill, n, 1); + } + } + else + { + if ((Csegment->flags | sym->flags) & SYM_UNKNOWN) { + ++Redo; + Redo_why |= REASON_ALIGN_NORMAL_ORIGIN_NOT_KNOWN; + } + else + { + long n = sym->value - (Csegment->org % sym->value); + if (n != sym->value) + genfill(fill, n, 1); + } + } + FreeSymbolList(sym); + programlabel(); +} + +void +v_subroutine(char *str, MNEMONIC *dummy) +{ + ++Lastlocalindex; + Localindex = Lastlocalindex; + programlabel(); +} + +void +v_equ(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym = eval(str, 0); + SYMBOL *lab; + + + /* + * If we encounter a line of the form + * . = expr ; or . EQU expr + * treat it as one of + * org expr + * rorg expr + * depending on whether we have a relocatable origin now or not. + */ + if (strlen(Av[0]) == 1 && (Av[0][0] == '.' + || (Av[0][0] == '*' && (Av[0][0] = '.') && 1) /*AD: huh?*/ + )) { + /* Av[0][0] = '\0'; */ + if (Csegment->flags & SF_RORG) + { + v_rorg(str, dummy); + } + else + { + v_org(str, dummy); + } + return; + } + + + lab = findsymbol(Av[0], strlen(Av[0])); + if (!lab) + lab = CreateSymbol( Av[0], strlen(Av[0]) ); + if (!(lab->flags & SYM_UNKNOWN)) + { + if (sym->flags & SYM_UNKNOWN) + { + ++Redo; + Redo_why |= REASON_EQU_NOT_RESOLVED; + } + else + { + if (lab->value != sym->value) + { + asmerr( ERROR_EQU_VALUE_MISMATCH, false, NULL ); + printf("old value: $%04lx new value: $%04lx\n", + lab->value, sym->value); + ++Redo; + Redo_why |= REASON_EQU_VALUE_MISMATCH; + } + } + } + + lab->value = sym->value; + lab->flags = sym->flags & (SYM_UNKNOWN|SYM_STRING); + lab->string = sym->string; + sym->flags &= ~(SYM_STRING|SYM_MACRO); + + /* List the value */ + { + unsigned long v = lab->value; + + Glen = 0; + if (v > 0x0000FFFF) + { + Gen[Glen++] = v >> 24; + Gen[Glen++] = v >> 16; + } + Gen[Glen++] = v >> 8; + Gen[Glen++] = v; + } + + + FreeSymbolList(sym); +} + +void +v_eqm(char *str, MNEMONIC *dummy) +{ + SYMBOL *lab; + int len = strlen(Av[0]); + + if ((lab = findsymbol(Av[0], len)) != NULL) { + if (lab->flags & SYM_STRING) + free(lab->string); + } + else + { + lab = CreateSymbol( Av[0], len ); + } + lab->value = 0; + lab->flags = SYM_STRING | SYM_SET | SYM_MACRO; + lab->string = strcpy(ckmalloc(strlen(str)+1), str); +} + +void +v_echo(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym = eval(str, 0); + SYMBOL *s; + char buf[256]; + + for (s = sym; s; s = s->next) { + if (!(s->flags & SYM_UNKNOWN)) { + if (s->flags & (SYM_MACRO|SYM_STRING)) + sprintf(buf,"%s", s->string); + else + sprintf(buf,"$%lx", s->value); + if (FI_listfile) + fprintf(FI_listfile, " %s", buf); + printf(" %s", buf); + } + } + puts(""); + if (FI_listfile) + putc('\n', FI_listfile); +} + +void v_set(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym = eval(str, 0); + SYMBOL *lab; + + lab = findsymbol(Av[0], strlen(Av[0])); + if (!lab) + lab = CreateSymbol( Av[0], strlen(Av[0]) ); + lab->value = sym->value; + lab->flags = sym->flags & (SYM_UNKNOWN|SYM_STRING); + lab->string = sym->string; + sym->flags &= ~(SYM_STRING|SYM_MACRO); + FreeSymbolList(sym); +} + +void +v_execmac(char *str, MACRO *mac) +{ + INCFILE *inc; + STRLIST *base; + STRLIST **psl, *sl; + char *s1; + + programlabel(); + + if (Mlevel == MAXMACLEVEL) { + puts("infinite macro recursion"); + return; + } + ++Mlevel; + base = (STRLIST *)ckmalloc(sizeof(STRLIST)-STRLISTSIZE+strlen(str)+1); + base->next = NULL; + strcpy(base->buf, str); + psl = &base->next; + while (*str && *str != '\n') { + s1 = str; + while (*str && *str != '\n' && *str != ',') + ++str; + sl = (STRLIST *)ckmalloc(sizeof(STRLIST)-STRLISTSIZE+1+(str-s1)); + sl->next = NULL; + *psl = sl; + psl = &sl->next; + memcpy(sl->buf, s1, (str-s1)); + sl->buf[str-s1] = 0; + if (*str == ',') + ++str; + while (*str == ' ') + ++str; + } + + inc = (INCFILE *)zmalloc(sizeof(INCFILE)); + inc->next = pIncfile; + inc->name = mac->name; + inc->fi = pIncfile->fi; /* garbage */ + inc->lineno = 0; + inc->flags = INF_MACRO; + inc->saveidx = Localindex; + + inc->savedolidx = Localdollarindex; + + inc->strlist = mac->strlist; + inc->args = base; + pIncfile = inc; + + ++Lastlocalindex; + Localindex = Lastlocalindex; + + ++Lastlocaldollarindex; + Localdollarindex = Lastlocaldollarindex; + +} + +void v_end(char *str, MNEMONIC *dummy) +{ + /* Only ENDs current file and any macro calls within it */ + + while ( pIncfile->flags & INF_MACRO) + v_endm(NULL, NULL); + + fseek( pIncfile->fi, 0, SEEK_END); +} + +void +v_endm(char *str, MNEMONIC *dummy) +{ + INCFILE *inc = pIncfile; + STRLIST *args, *an; + + /* programlabel(); contrary to documentation */ + if (inc->flags & INF_MACRO) { + --Mlevel; + for (args = inc->args; args; args = an) { + an = args->next; + free(args); + } + Localindex = inc->saveidx; + + Localdollarindex = inc->savedolidx; + + pIncfile = inc->next; + free(inc); + return; + } + puts("not within a macro"); +} + +void +v_mexit(char *str, MNEMONIC *dummy) +{ + v_endm(NULL, NULL); +} + +void +v_ifconst(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym; + + programlabel(); + sym = eval(str, 0); + pushif(sym->flags == 0); + FreeSymbolList(sym); +} + +void +v_ifnconst(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym; + + programlabel(); + sym = eval(str, 0); + pushif(sym->flags != 0); + FreeSymbolList(sym); +} + +void +v_if(char *str, MNEMONIC *dummy) +{ + SYMBOL *sym; + + if (!Ifstack->xtrue || !Ifstack->acctrue) { + pushif(0); + return; + } + programlabel(); + sym = eval(str, 0); + if (sym->flags) { + ++Redo; + Redo_why |= REASON_IF_NOT_RESOLVED; + pushif(0); + Ifstack->acctrue = 0; + + Redo_if |= 1; + + } + else + { + pushif(!!sym->value); + } + FreeSymbolList(sym); +} + +void v_else(char *str, MNEMONIC *dummy) +{ + if (Ifstack->acctrue && !(Ifstack->flags & IFF_BASE)) { + programlabel(); + Ifstack->xtrue = !Ifstack->xtrue; + } +} + +void +v_endif(char *str, MNEMONIC *dummy) +{ + IFSTACK *ifs = Ifstack; + + if (!(ifs->flags & IFF_BASE)) { + if (ifs->acctrue) + programlabel(); + if (ifs->file != pIncfile) { + puts("too many endif's"); + } + else + { + Ifstack = ifs->next; + free(ifs); + } + } +} + +void v_repeat(char *str, MNEMONIC *dummy) +{ + REPLOOP *rp; + SYMBOL *sym; + + if (!Ifstack->xtrue || !Ifstack->acctrue) { + pushif(0); + return; + } + programlabel(); + sym = eval(str, 0); + if (sym->value == 0) { + pushif(0); + FreeSymbolList(sym); + return; + } + +#ifdef DAD + + /* Don't allow negative values for REPEAT loops */ + + if ( sym->value < 0 ) + { + pushif( 0 ); + FreeSymbolList( sym ); + + asmerr( ERROR_REPEAT_NEGATIVE, false, NULL ); + return; + } + +#endif + + rp = (REPLOOP *)zmalloc(sizeof(REPLOOP)); + rp->next = Reploop; + rp->file = pIncfile; + if (pIncfile->flags & INF_MACRO) + rp->seek = (long)pIncfile->strlist; + else + rp->seek = ftell(pIncfile->fi); + rp->lineno = pIncfile->lineno; + rp->count = sym->value; + if ((rp->flags = sym->flags) != 0) { + ++Redo; + Redo_why |= REASON_REPEAT_NOT_RESOLVED; + } + Reploop = rp; + FreeSymbolList(sym); + pushif(1); +} + +void +v_repend(char *str, MNEMONIC *dummy) +{ + if (!Ifstack->xtrue || !Ifstack->acctrue) { + v_endif(NULL,NULL); + return; + } + if (Reploop && Reploop->file == pIncfile) { + if (Reploop->flags == 0 && --Reploop->count) { + if (pIncfile->flags & INF_MACRO) + pIncfile->strlist = (STRLIST *)Reploop->seek; + else + fseek(pIncfile->fi,Reploop->seek,0); + pIncfile->lineno = Reploop->lineno; + } + else + { + rmnode((void **)&Reploop, sizeof(REPLOOP)); + v_endif(NULL,NULL); + } + return; + } + puts("no repeat"); +} + + + +STRLIST *incdirlist; + +void +v_incdir(char *str, MNEMONIC *dummy) +{ + STRLIST **tail; + char *buf; + int found = 0; + + buf = getfilename(str); + + for (tail = &incdirlist; *tail; tail = &(*tail)->next) { + if (strcmp((*tail)->buf, buf) == 0) + found = 1; + } + + if (!found) { + STRLIST *newdir; + + newdir = (STRLIST *)permalloc(STRLISTSIZE + 1 + strlen(buf)); + strcpy(newdir->buf, buf); + *tail = newdir; + } + + if (buf != str) + free(buf); +} + +void +addpart(char *dest, const char *dir, const char *file) +{ +#if 0 /* not needed here */ + if (strchr(file, ':')) { + strcpy(dest, file); + } + else +#endif + { + int pos; + + strcpy(dest, dir); + pos = strlen(dest); + if (pos > 0 && dest[pos-1] != ':' && dest[pos-1] != '/') { + dest[pos] = '/'; + pos++; + } + strcpy(dest + pos, file); + } +} + +FILE * +pfopen(const char *name, const char *mode) +{ + FILE *f; + STRLIST *incdir; + char *buf; + + f = fopen(name, mode); + if (f) + return f; + + /* Don't use the incdirlist for absolute pathnames */ + if (strchr(name, ':')) + return NULL; + + buf = zmalloc(512); + + for (incdir = incdirlist; incdir; incdir = incdir->next) { + addpart(buf, incdir->buf, name); + + f = fopen(buf, mode); + if (f) + break; + } + + free(buf); + return f; +} + + +static long Seglen; +static long Seekback; + +void +generate(void) +{ + long seekpos; + static unsigned long org; + int i; + + if (!Redo) + { + if (!(Csegment->flags & SF_BSS)) + { + for (i = Glen - 1; i >= 0; --i) + CheckSum += Gen[i]; + + if (Fisclear) + { + Fisclear = 0; + if (Csegment->flags & SF_UNKNOWN) + { + ++Redo; + Redo_why |= REASON_OBSCURE; + return; + } + + org = Csegment->org; + + if ( F_format < FORMAT_RAW ) + { + putc((org & 0xFF), FI_temp); + putc(((org >> 8) & 0xFF), FI_temp); + + if ( F_format == FORMAT_RAS ) + { + Seekback = ftell(FI_temp); + Seglen = 0; + putc(0, FI_temp); + putc(0, FI_temp); + } + } + } + + switch(F_format) + { + + default: + + asmerr( ERROR_BAD_FORMAT, true, "Unhandled internal format specifier" ); + break; + + case FORMAT_RAW: + case FORMAT_DEFAULT: + + if (Csegment->org < org) + { + printf("segment: %s %s vs current org: %04lx\n", + Csegment->name, sftos(Csegment->org, Csegment->flags), org); + asmerr( ERROR_ORIGIN_REVERSE_INDEXED, true, NULL ); + exit(1); + } + + while (Csegment->org != org) + { + putc(OrgFill, FI_temp); + ++org; + } + + fwrite(Gen, Glen, 1, FI_temp); + break; + + case FORMAT_RAS: + + if (org != Csegment->org) + { + org = Csegment->org; + seekpos = ftell(FI_temp); + fseek(FI_temp, Seekback, 0); + putc((Seglen & 0xFF), FI_temp); + putc(((Seglen >> 8) & 0xFF), FI_temp); + fseek(FI_temp, seekpos, 0); + putc((org & 0xFF), FI_temp); + putc(((org >> 8) & 0xFF), FI_temp); + Seekback = ftell(FI_temp); + Seglen = 0; + putc(0, FI_temp); + putc(0, FI_temp); + } + + fwrite(Gen, Glen, 1, FI_temp); + Seglen += Glen; + break; + + } + org += Glen; + } + } + + Csegment->org += Glen; + + if (Csegment->flags & SF_RORG) + Csegment->rorg += Glen; +} + +void closegenerate(void) +{ + if (!Redo) + { + if ( F_format == FORMAT_RAS ) + { + fseek(FI_temp, Seekback, 0); + putc((Seglen & 0xFF), FI_temp); + putc(((Seglen >> 8) & 0xFF), FI_temp); + fseek(FI_temp, 0L, 2); + } + } +} + +void +genfill(long fill, long entries, int size) +{ + long bytes = entries; /* multiplied later */ + int i; + unsigned char c3,c2,c1,c0; + + if (!bytes) + return; + + c3 = fill >> 24; + c2 = fill >> 16; + c1 = fill >> 8; + c0 = fill; + switch(size) + { + case 1: + memset(Gen, c0, sizeof(Gen)); + break; + + case 2: + bytes <<= 1; + for (i = 0; i < sizeof(Gen); i += 2) + { + if (MsbOrder) + { + Gen[i+0] = c1; + Gen[i+1] = c0; + } + else + { + Gen[i+0] = c0; + Gen[i+1] = c1; + } + } + break; + + case 4: + bytes <<= 2; + for (i = 0; i < sizeof(Gen); i += 4) + { + if (MsbOrder) + { + Gen[i+0] = c3; + Gen[i+1] = c2; + Gen[i+2] = c1; + Gen[i+3] = c0; + } + else + { + Gen[i+0] = c0; + Gen[i+1] = c1; + Gen[i+2] = c2; + Gen[i+3] = c3; + } + } + break; + } + + for (Glen = sizeof(Gen); bytes > sizeof(Gen); bytes -= sizeof(Gen)) + generate(); + Glen = bytes; + generate(); +} + +void +pushif(bool xbool) +{ + IFSTACK *ifs = (IFSTACK *)zmalloc(sizeof(IFSTACK)); + ifs->next = Ifstack; + ifs->file = pIncfile; + ifs->flags = 0; + ifs->xtrue = xbool; + ifs->acctrue = Ifstack->acctrue && Ifstack->xtrue; + Ifstack = ifs; +} diff --git a/src/symbols.c b/src/symbols.c new file mode 100644 index 00000000..f90a2800 --- /dev/null +++ b/src/symbols.c @@ -0,0 +1,265 @@ +/* +DASM Assembler +Portions of this code are Copyright (C)1988 Matthew Dillon +and (C) 1995 Olaf Seibert, (C)2003 Andrew Davie + +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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* +* SYMBOLS.C +* +* (c)Copyright 1988, Matthew Dillon, All Rights Reserved. +*/ + +#include "asm.h" + + +static unsigned int hash1(char *str, int len); +SYMBOL *allocsymbol(void); + +static SYMBOL org; +static SYMBOL special; +static SYMBOL specchk; + +void setspecial(int value, int flags) +{ + special.value = value; + special.flags = flags; +} + +SYMBOL *findsymbol(char *str, int len) +{ + unsigned int h1; + SYMBOL *sym; + char buf[MAX_SYM_LEN + 14]; /* historical */ + + if ( len > MAX_SYM_LEN ) + len = MAX_SYM_LEN; + + if (str[0] == '.') + { + if (len == 1) + { + if (Csegment->flags & SF_RORG) + { + org.flags = Csegment->rflags & SYM_UNKNOWN; + org.value = Csegment->rorg; + } + else + { + org.flags = Csegment->flags & SYM_UNKNOWN; + org.value = Csegment->org; + } + return &org; + } + if (len == 2 && str[1] == '.') + return &special; + if (len == 3 && str[1] == '.' && str[2] == '.') + { + specchk.flags = 0; + specchk.value = CheckSum; + return &specchk; + } + sprintf(buf, "%ld%.*s", Localindex, len, str); + len = strlen(buf); + str = buf; + } + + else if (str[len - 1] == '$') + { + sprintf(buf, "%ld$%.*s", Localdollarindex, len, str); + len = strlen(buf); + str = buf; + } + + h1 = hash1(str, len); + for (sym = SHash[h1]; sym; sym = sym->next) + { + if ((sym->namelen == len) && !memcmp(sym->name, str, len)) + break; + } + return sym; +} + +SYMBOL *CreateSymbol( char *str, int len ) +{ + SYMBOL *sym; + unsigned int h1; + char buf[ MAX_SYM_LEN + 14 ]; /* historical */ + + if (len > MAX_SYM_LEN ) + len = MAX_SYM_LEN; + + if (str[0] == '.') + { + sprintf(buf, "%ld%.*s", Localindex, len, str); + len = strlen(buf); + str = buf; + } + + + else if (str[len - 1] == '$') + { + sprintf(buf, "%ld$%.*s", Localdollarindex, len, str); + len = strlen(buf); + str = buf; + } + + sym = allocsymbol(); + sym->name = permalloc(len+1); + memcpy(sym->name, str, len); /* permalloc zeros the array for us */ + sym->namelen = len; + h1 = hash1(str, len); + sym->next = SHash[h1]; + sym->flags= SYM_UNKNOWN; + SHash[h1] = sym; + return sym; +} + +static unsigned int hash1(char *str, int len) +{ + unsigned int result = 0; + + while (len--) + result = (result << 2) ^ *str++; + return result & SHASHAND; +} + +/* +* Label Support Routines +*/ + +void programlabel(void) +{ + int len; + SYMBOL *sym; + SEGMENT *cseg = Csegment; + char *str; + unsigned char rorg = cseg->flags & SF_RORG; + unsigned char cflags = (rorg) ? cseg->rflags : cseg->flags; + unsigned long pc = (rorg) ? cseg->rorg : cseg->org; + + Plab = cseg->org; + Pflags = cseg->flags; + str = Av[0]; + if (*str == 0) + return; + len = strlen(str); + + + if (str[len-1] == ':') + --len; + + if (str[0] != '.' && str[len-1] != '$') + { + Lastlocaldollarindex++; + Localdollarindex = Lastlocaldollarindex; + } + + /* + * Redo: unknown and referenced + * referenced and origin not known + * known and phase error (origin known) + */ + + if ((sym = findsymbol(str, len)) != NULL) + { + if ((sym->flags & (SYM_UNKNOWN|SYM_REF)) == (SYM_UNKNOWN|SYM_REF)) + { + ++Redo; + Redo_why |= REASON_FORWARD_REFERENCE; + if (Xdebug) + printf("redo 13: '%s' %04x %04x\n", sym->name, sym->flags, cflags); + } + else if ((cflags & SYM_UNKNOWN) && (sym->flags & SYM_REF)) + { + ++Redo; + Redo_why |= REASON_FORWARD_REFERENCE; + } + else if (!(cflags & SYM_UNKNOWN) && !(sym->flags & SYM_UNKNOWN)) + { + if (pc != sym->value) + { + + /* + * If we had an unevaluated IF expression in the + * previous pass, don't complain about phase errors + * too loudly. + */ + if (F_verbose >= 1 || !(Redo_if & (REASON_OBSCURE))) + { + char sBuffer[ MAX_SYM_LEN * 2 ]; + sprintf( sBuffer, "%s %s", sym->name, sftos( sym->value, 0 ) ); + /*, sftos(sym->value, + sym->flags) ); , sftos(pc, cflags & 7));*/ + asmerr( ERROR_LABEL_MISMATCH, false, sBuffer ); + } + ++Redo; + Redo_why |= REASON_PHASE_ERROR; + } + } + } + else + { + sym = CreateSymbol( str, len ); + } + sym->value = pc; + sym->flags = (sym->flags & ~SYM_UNKNOWN) | (cflags & SYM_UNKNOWN); +} + +SYMBOL *SymAlloc; + +SYMBOL *allocsymbol(void) +{ + SYMBOL *sym; + + if (SymAlloc) + { + sym = SymAlloc; + SymAlloc = SymAlloc->next; + memset(sym, 0, sizeof(SYMBOL)); + } + else + { + sym = (SYMBOL *)permalloc(sizeof(SYMBOL)); + } + return sym; +} + +void freesymbol(SYMBOL *sym) +{ + sym->next = SymAlloc; + SymAlloc = sym; +} + + + +void FreeSymbolList(SYMBOL *sym) +{ + SYMBOL *next; + + while (sym) + { + next = sym->next; + sym->next = SymAlloc; + if (sym->flags & SYM_STRING) + free(sym->string); + SymAlloc = sym; + sym = next; + } +} + diff --git a/test/demo.asm b/test/demo.asm new file mode 100644 index 00000000..33ab3287 --- /dev/null +++ b/test/demo.asm @@ -0,0 +1,49 @@ +;;; +; +; Some useful macros and techniques +; + processor 6502 + +;;; + mac hexdig + + if [{1}] <= 9 + dc.b '0 + [{1}] + else + dc.b 'a + [{1}] - 10 + endif + + endm +;;; + mac hexnum + + if [{1}] >= $10 + hexnum [{1}] >> 4 + endif + hexdig [{1}] & $0F + + endm +;;; + + org 0 + hexnum $123ab + +;;;; +; +; Using an uninitialised segment to create C-like 'struct's. +; (idea taken from IBM-370 assembler style "dummy segments") + + seg.u node + org 0 + +s_next ds.b 2 ; a node has a pointer to the next one +s_data ds.b 2 ; and 2 bytes of data +s_more ds.b 3 ; and 3 bytes of something more + + seg code + +ptr equ 42 ; dummy value + ldy #s_data + lda (ptr),y ; get first byte of data + + diff --git a/test/example.asm b/test/example.asm new file mode 100644 index 00000000..eb772400 --- /dev/null +++ b/test/example.asm @@ -0,0 +1,293 @@ + +; EXAMPLE.ASM (6502 Microprocessor) +; + + processor 6502 + + mac ldax + lda [{1}] + ldx [{1}]+1 + endm + mac ldaxi + lda #<[{1}] + ldx #>[{1}] + endm + mac stax + sta [{1}] + stx [{1}]+1 + endm + mac pushxy + txa + pha + tya + pha + endm + mac popxy + pla + tay + pla + tax + endm + mac inc16 + inc {1} + bne .1 + inc {1}+1 +.1 + endm + +STOP1 equ %00000000 ;CxCTL 1 Stop bit +STOP2 equ %10000000 ;CxCTL 2 Stop bits (WL5:1.5, WL8&par:1) +WL5 equ %01100000 ;CxCTL Wordlength +WL6 equ %01000000 +WL7 equ %00100000 +WL8 equ %00000000 +RCS equ %00010000 ;CxCTL 1=Select baud, 0=ext. receiver clk + +B76800 equ %0000 ;CxCTL Baud rates (1.2288 Mhz clock) +B75 equ %0001 +B100 equ %0010 +B150 equ %0011 +B200 equ %0100 +B300 equ %0101 +B400 equ %0110 +B600 equ %0111 +B800 equ %1000 +B1200 equ %1001 +B1600 equ %1010 +B2400 equ %1011 +B3200 equ %1100 +B4800 equ %1101 +B6400 equ %1110 +B12800 equ %1111 + +PARODD equ %00100000 ;CxCMD Select Parity +PAREVEN equ %01100000 +PARMARK equ %10100000 +PARSPACE equ %11100000 +PAROFF equ %00000000 + +RECECHO equ %00010000 ;CxCMD Receiver Echo mode +TMASK equ %00001100 +TDISABLE equ %00000000 ;CxCMD Transmitter modes +TDISABLER equ %00001000 ;RTS stays asserted +TENABLE equ %00000100 +TBREAK equ %00001100 ;send break + +UA_IRQDSBL equ %00000010 +DTRRDY equ %00000001 ;~DTR output is inverted (low) + +SR_PE equ %00000001 ;CxSTAT Status +SR_FE equ %00000010 ;NOTE: writing dummy data causes RESET +SR_OVRUN equ %00000100 +SR_RDRFULL equ %00001000 +SR_TDREMPTY equ %00010000 +SR_DCD equ %00100000 +SR_DSR equ %01000000 +SR_INTPEND equ %10000000 + + +T1_OEPB7 equ %10000000 ;x_ACR +T1_FREERUN equ %01000000 ;T1 free running mode +T1_ONESHOT equ %00000000 +T2_ICPB6 equ %00100000 ;T2 counts pulses on PB6 +T2_ONESHOT equ %00000000 ;T2 counts phase2 transitions +SRC_OFF equ %00000000 ;shift register control +SRC_INT2 equ %00000100 +SRC_INPH2 equ %00001000 +SRC_INEXT equ %00001100 +SRC_OUTFR equ %00010000 ;free running output using T2 +SRC_OUTT2 equ %00010100 +SRC_OUTPH2 equ %00011000 +SRC_OUTEXT equ %00011100 +PBLE equ %00000010 ;on CB1 transition (in/out). +PALE equ %00000001 ;on CA1 transition (in). data retained + + ;x_PCR +CB2_I_NEG equ %00000000 ;interrupt on neg trans, r/w ORB clears +CB2_I_NEGI equ %00100000 ; same, but r/w ORB does not clear int +CB2_I_POS equ %01000000 ;interrupt on pos trans, r/w ORB clears +CB2_I_POSI equ %01100000 ; same, but r/w ORB does not clear int +CB2_O_HSHAK equ %10000000 ;CB2=0 on r/w ORB, CB2=1 on CB1 transition +CB2_O_PULSE equ %10100000 ;CB2=0 for one clock after r/w ORB +CB2_O_MANLO equ %11000000 ;CB2=0 +CB2_O_MANHI equ %11100000 ;CB2=1 + +CA2_I_NEG equ %00000000 ;interrupt on neg trans, r/w ORA clears +CA2_I_NEGI equ %00100000 ; same, but r/w ORA does not clear int +CA2_I_POS equ %01000000 ;interrupt on pos trans, r/w ORA clears +CA2_I_POSI equ %01100000 ; same, but r/w ORA does not clear int +CA2_O_HSHAK equ %10000000 ;CA2=0 on r/w ORA, CA2=1 on CA1 transition +CA2_O_PULSE equ %10100000 ;CA2=0 for one clock after r/w ORA +CA2_O_MANLO equ %11000000 ;CA2=0 +CA2_O_MANHI equ %11100000 ;CA2=1 + + +CB1_THI equ %00010000 +CB1_TLO equ %00000000 +CA1_THI equ %00000001 +CA1_TLO equ %00000000 + +VIRPEND equ %10000000 ;x_IFR +IRENABLE equ %10000000 ;x_IER 1's enable ints 0=no change +IRDISABLE equ %00000000 ;x_IER 1's disable ints 0=no change + +IRT1 equ %01000000 +IRT2 equ %00100000 +IRCB1 equ %00010000 +IRCB2 equ %00001000 +IRSR equ %00000100 +IRCA1 equ %00000010 +IRCA2 equ %00000001 + + seg.u bss + org $0000 ;RAM (see below) + org $2000 ;unused + org $4000 ;unused + + org $6000 ;6551 CHANNEL #1 +C1DATA ds 1 +C1STAT ds 1 +C1CMD ds 1 +C1CTL ds 1 + + org $8000 ;6551 CHANNEL #2 +C2DATA ds 1 +C2STAT ds 1 +C2CMD ds 1 +C2CTL ds 1 + + org $A000 ;6522 (HOST COMM) +H_ORB ds 1 +H_ORAHS ds 1 ;with CA2 handshake +H_DDRB ds 1 +H_DDRA ds 1 +H_T1CL ds 1 ;read clears interrupt flag +H_T1CH ds 1 ;write clears interrupt flag +H_T1CLL ds 1 +H_T1CHL ds 1 ;write clears interrupt flag +H_T2CL ds 1 ;read clears interrupt flag +H_T2CH ds 1 ;write clears interrupt flag +H_SR ds 1 +H_ACR ds 1 +H_PCR ds 1 +H_IFR ds 1 +H_IER ds 1 +H_ORA ds 1 ;no CA2 handshake + + org $C000 ;6522 (IO COMM) +I_ORB ds 1 +I_ORAHS ds 1 ; (same comments apply) +I_DDRB ds 1 +I_DDRA ds 1 +I_T1CL ds 1 +I_T1CH ds 1 +I_T1CLL ds 1 +I_T1CHL ds 1 +I_T2CL ds 1 +I_T2CH ds 1 +I_SR ds 1 +I_ACR ds 1 +I_PCR ds 1 +I_IFR ds 1 +I_IER ds 1 +I_ORA ds 1 + + + + ; -------------------------- ZERO PAGE ------------------- + seg.u data + org $00 + + ; -------------------------- NORMAL RAM ------------------- + org $0100 + +RAMEND equ $2000 + + ; -------------------------- CODE ------------------- + + seg code + org $F000 +PROMBEG equ . + +RESET subroutine + sei ;disable interrupts + ldx #$FF ;reset stack + txs + + lda #$FF + sta H_DDRA + sta C1STAT ;reset 6551#1 (garbage data) + sta C2STAT ;reset 6551#2 + lda #$7F ;disable all 6522 interrupts + sta H_IER + sta I_IER + + lda #%00010000 ;76.8 baud, 8 bits, 1 stop + sta C1CTL + lda #%00000101 ;no parity, enable transmitter & int + sta C1CMD + lda #$AA ;begin transmision + sta C1DATA + + lda #%00011111 ;9600 baud, 8 bits, 1 stop + sta C2CTL + lda #%00000101 + sta C2CMD + lda #$41 + sta C2DATA + + cli ;enable interrupts + +.1 jsr LOAD + jsr SAVE + jmp .1 + +LOAD subroutine + + ldx #0 +.1 txa + sta $0500,x + inx + bne .1 + rts + +SAVE subroutine + + ldx #0 +.2 lda $0500,x + sta H_ORA + inx + bne .2 + rts + +NMI rti + + subroutine +IRQ bit C1STAT + bpl .1 + pha + lda #$AA + sta C1DATA + lda C1DATA + pla + rti +.1 bit C2STAT + bpl .2 + pha + lda #$41 + sta C2DATA + lda C2DATA + pla +.2 rti + + ; VECTOR ------------------------------------------------ + + seg vector + org $FFFA + dc.w NMI + dc.w RESET + dc.w IRQ + +PROMEND equ . + + diff --git a/test/locals.asm b/test/locals.asm new file mode 100644 index 00000000..dc51e328 --- /dev/null +++ b/test/locals.asm @@ -0,0 +1,40 @@ +;;;; +; +; Test local symbols +; + processor 6502 + + mac test1 + bne .end +test$ = 1 + test2 +.end + nop + endm + + mac test2 + bne .end +test$ = 1 + test3 +.end + nop + endm + + mac test3 + bne .end +test$ = 1 + nop +.end + nop + endm + + org 0 + + test1 + test2 + test3 + +.end + +loop set 0 + diff --git a/test/suite6303.asm b/test/suite6303.asm new file mode 100644 index 00000000..abb60167 --- /dev/null +++ b/test/suite6303.asm @@ -0,0 +1,235 @@ + + processor hd6303 + org 0 + + adda #10 ; 8B 0A + adda 10 ; 9B 0A + adda 10,x ; AB 0A + adda 1000 ; BB 03 E8 + addb #10 ; CB 0A + addb 10 ; DB 0A + addb 10,x ; EB 0A + addb 1000 ; FB 03 E8 + addd #1000 ; C3 03 E8 + addd 10 ; D3 0A + addd 10,x ; E3 0A + addd 1000 ; F3 03 E8 + aba ; 1B + adca #10 ; 89 0A + adca 10 ; 99 0A + adca 10,x ; A9 0A + adca 1000 ; B9 03 E8 + adcb #10 ; C9 + adcb 10 ; D9 + adcb 10,x ; E9 + adcb 1000 ; F9 03 E8 + anda #10 ; 84 0A + anda 10 ; 94 0A + anda 10,x ; A4 0A + anda 1000 ; B4 03 E8 + andb #10 ; C4 0A + andb 10 ; D4 0A + andb 10,x ; E4 0A + andb 1000 ; F4 03 E8 + bita #10 ; 85 0A + bita 10 ; 95 0A + bita 10,x ; A5 0A + bita 1000 ; B5 03 E8 + bitb #10 ; C5 0A + bitb 10 ; D5 0A + bitb 10,x ; E5 0A + bitb 1000 ; F5 03 E8 + clr 10,x ; 6F 0A + clr 1000 ; 7F 03 E8 + clra ; 4F + clrb ; 5F + cmpa #10 ; 81 0A + cmpa 10 ; 91 0A + cmpa 10,x ; A1 0A + cmpa 1000 ; B1 03 E8 + cmpb #10 ; C1 0A + cmpb 10 ; D1 0A + cmpb 10,x ; E1 0A + cmpb 1000 ; F1 03 E8 + cba ; 11 + com 10,x ; 63 0A + com 1000 ; 73 03 E8 + coma ; 43 + comb ; 53 + neg 10,x ; 60 0A + neg 1000 ; 70 03 E8 + nega ; 40 + negb ; 50 + daa ; 19 + dec 10,x ; 6A 0A + dec 1000 ; 7A 03 E8 + deca ; 4A + decb ; 5A + eora #10 ; 88 0A + eora 10 ; 98 0A + eora 10,x ; A8 0A + eora 1000 ; B8 03 E8 + eorb #10 ; C8 0A + eorb 10 ; D8 0A + eorb 10,x ; E8 0A + eorb 1000 ; F8 03 E8 + inc 10,x ; 6C 0A + inc 1000 ; 7C 03 E8 + inca ; 4C + incb ; 5C + ldaa #10 ; 86 0A + ldaa 10 ; 96 0A + ldaa 10,x ; A6 0A + ldaa 1000 ; B6 03 E8 + ldab #10 ; C6 0A + ldab 10 ; D6 0A + ldab 10,x ; E6 0A + ldab 1000 ; F6 03 E8 + ldd #1000 ; CC 03 E8 + ldd 10 ; DC 0A + ldd 10,x ; EC 0A + ldd 1000 ; FC 03 E8 + mul ; 3D + oraa #10 ; 8A 0A + oraa 10 ; 9A 0A + oraa 10,x ; AA 0A + oraa 1000 ; BA 03 E8 + orab #10 ; CA 0A + orab 10 ; DA 0A + orab 10,x ; EA 0A + orab 1000 ; FA 03 E8 + psha ; 36 + pshb ; 37 + pula ; 32 + pulb ; 33 + rol 10,x ; 69 0A + rol 1000 ; 79 03 E8 + rola ; 49 + rolb ; 59 + ror 10,x ; 66 0A + ror 1000 ; 76 03 E8 + rora ; 46 + rorb ; 56 + asl 10,x ; 68 0A + asl 1000 ; 78 03 E8 + asla ; 48 + aslb ; 58 + asld ; 05 + asr 10,x ; 67 0A + asr 1000 ; 77 03 E8 + asra ; 47 + asrb ; 57 + lsr 10,x ; 64 0A + lsr 1000 ; 74 03 E8 + lsra ; 44 + lsrb ; 54 + lsrd ; 04 + staa 10 ; 97 0A + staa 10,x ; A7 0A + staa 1000 ; B7 03 E8 + stab 10 ; D7 0A + stab 10,x ; E7 0A + stab 1000 ; F7 03 E8 + std 10 ; DD 0A + std 10,x ; ED 0A + std 1000 ; FD 03 E8 + suba #10 ; 80 0A + suba 10 ; 90 0A + suba 10,x ; A0 0A + suba 1000 ; B0 03 E8 + subb #10 ; C0 0A + subb 10 ; D0 0A + subb 10,x ; E0 0A + subb 1000 ; F0 03 E8 + subd #1000 ; 83 03 E8 + subd 10 ; 93 0A + subd 10,x ; A3 0A + subd 1000 ; B3 03 E8 + sba ; 10 + sbca #10 ; 82 0A + sbca 10 ; 92 0A + sbca 10,x ; A2 0A + sbca 1000 ; B2 03 E8 + sbcb #10 ; C2 0A + sbcb 10 ; D2 0A + sbcb 10,x ; E2 0A + sbcb 1000 ; F2 03 E8 + tab ; 16 + tba ; 17 + tst 10,x ; 6D 0A + tst 1000 ; 7D 03 E8 + tsta ; 4D + tstb ; 5D + aim 10 ; 71 0A + aim 10,x ; 61 0A + oim 10 ; 72 0A + oim 10,x ; 62 0A + eim 10 ; 75 0A + eim 10,x ; 65 0A + tim 10 ; 7B 0A + tim 10,x ; 6B 0A + cpx #1000 ; 8C 03 E8 + cpx 10 ; 9C 0A + cpx 10,x ; AC 0A + cpx 1000 ; BC 03 E8 + dex ; 09 + des ; 34 + inx ; 08 + ins ; 31 + ldx #1000 ; CE 03 E8 + ldx 10 ; DE 0A + ldx 10,x ; EE 0A + ldx 1000 ; FE 03 E8 + lds #1000 ; 8E 03 E8 + lds 10 ; 9E 0A + lds 10,x ; AE 0A + lds 1000 ; BE 03 E8 + stx 10 ; DF 0A + stx 10,x ; EF 0A + stx 1000 ; FF 03 E8 + sts 10 ; 9F 0A + sts 10,x ; AF 0A + sts 1000 ; BF 03 E8 + txs ; 35 + tsx ; 30 + abx ; 3A + pshx ; 3C + pulx ; 38 + xgdx ; 18 + bra . ; 20 FE + brn . ; 21 FE + bcc . ; 24 FE + bcs . ; 25 FE + beq . ; 27 FE + bge . ; 2C FE + bgt . ; 2E FE + bhi . ; 22 FE + ble . ; 2F FE + bls . ; 23 FE + blt . ; 2D FE + bmi . ; 2B FE + bne . ; 26 FE + bvc . ; 28 FE + bvs . ; 29 FE + bpl . ; 2A FE + bsr . ; 8D FE + jmp 10,x ; 6E 0A + jmp 1000 ; 7E 03 E8 + jsr 10 ; 9D 0A + jsr 10,x ; AD 0A + jsr 1000 ; BD 03 E8 + nop ; 01 + rti ; 3B + rts ; 39 + swi ; 3F + wai ; 3E + slp ; 1A + clc ; 0C + cli ; 0E + clv ; 0A + sec ; 0D + sei ; 0F + sev ; 0B + tap ; 06 + tpa ; 07 + diff --git a/test/suite6502.asm b/test/suite6502.asm new file mode 100644 index 00000000..87fc804f --- /dev/null +++ b/test/suite6502.asm @@ -0,0 +1,206 @@ + + ; TEST ADDRESSING MODES + + processor 6502 + + org 0 + + adc #1 + adc 1 + adc 1,x + adc 1,y ;absolute + adc 1000 + adc 1000,x + adc 1000,y + adc (1,x) + adc (1),y + + and #1 + and 1 + and 1,x + and 1,y ;absolute + and 1000 + and 1000,x + and 1000,y + and (1,x) + and (1),y + + asl + asl 1 + asl 1,x + asl 1000 + asl 1000,x + + bcc . + bcs . + beq . + bit 1 + bit 1000 + bmi . + bne . + bpl . + brk + bvc . + bvs . + clc + cld + cli + clv + + cmp #1 + cmp 1 + cmp 1,x + cmp 1,y ;absolute + cmp 1000 + cmp 1000,x + cmp 1000,y + cmp (1,x) + cmp (1),y + + cpx #1 + cpx 1 + cpx 1000 + + cpy #1 + cpy 1 + cpy 1000 + + dec 1 + dec 1,x + dec 1000 + dec 1000,x + + dex + dey + + eor #1 + eor 1 + eor 1,x + eor 1,y ;absolute + eor 1000 + eor 1000,x + eor 1000,y + eor (1,x) + eor (1),y + + inc 1 + inc 1,x + inc 1000 + inc 1000,x + + inx + iny + + jmp 1 ;absolute + jmp 1000 + jmp (1) ;absolute + jmp (1000) + + jsr 1 ;absolute + jsr 1000 + + lda #1 + lda 1 + lda 1,x + lda 1,y ;absolute + lda 1000 + lda 1000,x + lda 1000,y + lda (1,x) + lda (1),y + + ldx #1 + ldx 1 + ldx 1,y + ldx 1000 + ldx 1000,y + + ldy #1 + ldy 1 + ldy 1,x + ldy 1000 + ldy 1000,x + + lsr + lsr 1 + lsr 1,x + lsr 1000 + lsr 1000,x + + nop + + ora #1 + ora 1 + ora 1,x + ora 1,y ;absolute + ora 1000 + ora 1000,x + ora 1000,y + ora (1,x) + ora (1),y + + pha + php + pla + plp + + rol + rol 1 + rol 1,x + rol 1000 + rol 1000,x + + ror + ror 1 + ror 1,x + ror 1000 + ror 1000,x + + rti + rts + + sbc #1 + sbc 1 + sbc 1,x + sbc 1,y ;absolute + sbc 1000 + sbc 1000,x + sbc 1000,y + sbc (1,x) + sbc (1),y + + sec + sed + sei + + sta 1 + sta 1,x + sta 1,y ;absolute + sta 1000 + sta 1000,x + sta 1000,y + sta (1,x) + sta (1),y + + stx 1 + stx 1,y + stx 1000 + + sty 1 + sty 1,x + sty 1000 + + tax + tay + tsx + txa + txs + tya + + ; illegal opcode additions + + lax (1),y + nop 0 + + + diff --git a/test/suite68705.asm b/test/suite68705.asm new file mode 100644 index 00000000..366ec10d --- /dev/null +++ b/test/suite68705.asm @@ -0,0 +1,225 @@ + + processor 68705 + + org 0 + adc #10 + adc 10 + adc 1000 + adc ,x + adc 1,x + adc 1000,x + add #10 + add 10 + add 1000 + add ,x + add 1,x + add 1000,x + + and #10 + and 10 + and 1000 + and ,x + and 1,x + and 1000,x + + asla + aslx + asl 10 + asl ,x + asl 10,x + + asra + asrx + asr 10 + asr ,x + asr 10,x + + bcc . + bclr 1,23 + bcs . + beq . + bhcc . + bhcs . + bhi . + bhs . + bih . + bil . + + bit #10 + bit 10 + bit 1000 + bit ,x + bit 1,x + bit 1000,x + + blo . + bls . + bmc . + bmi . + bms . + bne . + bpl . + bra . + brn . + brclr 1,10,. + brset 1,10,. + bset 1,10 + bsr . + + clc + cli + + clra + clrx + clr 10 + clr ,x + clr 10,x + + cmp #10 + cmp 10 + cmp 1000 + cmp ,x + cmp 1,x + cmp 1000,x + + coma + comx + com 10 + com ,x + com 10,x + + cpx #10 + cpx 10 + cpx 1000 + cpx ,x + cpx 10,x + cpx 1000,x + + deca + decx + dec 10 + dec ,x + dec 10,x + + eor #10 + eor 10 + eor 1000 + eor ,x + eor 10,x + eor 1000,x + + inca + incx + inc 10 + inc ,x + inc 10,x + + jmp 10 + jmp 1000 + jmp ,x + jmp 10,x + jmp 1000,x + + jsr 10 + jsr 1000 + jsr ,x + jsr 10,x + jsr 1000,x + + lda #10 + lda 10 + lda 1000 + lda ,x + lda 10,x + lda 1000,x + + ldx #10 + ldx 10 + ldx 1000 + ldx ,x + ldx 10,x + ldx 1000,x + + lsla + lslx + lsl 10 + lsl ,x + lsl 10,x + + lsra + lsrx + lsr 10 + lsr ,x + lsr 10,x + + nega + negx + neg 10 + neg ,x + neg 10,x + + nop + + ora #10 + ora 10 + ora 1000 + ora ,x + ora 10,x + ora 1000,x + + rola + rolx + rol 10 + rol ,x + rol 10,x + + rora + rorx + ror 10 + ror ,x + ror 10,x + + rsp + rti + rts + + sbc #10 + sbc 10 + sbc 1000 + sbc ,x + sbc 10,x + sbc 1000,x + + sec + sei + + sta 10 + sta 1000 + sta ,x + sta 10,x + sta 1000,x + + stx 10 + stx 1000 + stx ,x + stx 10,x + stx 1000,x + + sub #10 + sub 10 + sub 1000 + sub ,x + sub 10,x + sub 1000,x + + swi + tax + + tsta + tstx + tst 10 + tst ,x + tst 10,x + + txa + diff --git a/test/suite68HC11.asm b/test/suite68HC11.asm new file mode 100644 index 00000000..18e993b8 --- /dev/null +++ b/test/suite68HC11.asm @@ -0,0 +1,359 @@ + + + ; TEST ADDRESSING MODES + + processor 68HC11 + + org 0 + + aba + abx + aby + adca #1 + adca 1 + adca 1000 + adca 1,x + adca 1,y + adcb #1 + adcb 1 + adcb 1000 + adcb 1,x + adcb 1,y + adda #1 + adda 1 + adda 1000 + adda 1,x + adda 1,y + addb #1 + addb 1 + addb 1000 + addb 1,x + addb 1,y + addd #1000 + addd 1 + addd 1000 + addd 1,x + addd 1,y + anda #1 + anda 1 + anda 1000 + anda 1,x + anda 1,y + andb #1 + andb 1 + andb 1000 + andb 1,x + andb 1,y + asla + aslb + asl 1 ;extended + asl 1000 + asl 1,x + asl 1,y + asld + asra + asrb + asr 1 ;extended + asr 1000 + asr 1,x + asr 1,y + bcc . + bclr 1, $11 + bclr 1,x ,$22 + bclr 1,y ,$33 + bcs . + beq . + bge . + bgt . + bhi . + bhs . + bita #1 + bita 1 + bita 1000 + bita 1,x + bita 1,y + bitb #1 + bitb 1 + bitb 1000 + bitb 1,x + bitb 1,y + ble . + blo . + bls . + blt . + bmi . + bne . + bpl . + bra . + brclr 1, $11, . ; br??? direct-location, mask, branch-to + brclr 1,x , $22, . + brclr 1,y , $33, . + brn . + brset 1, $11, . + brset 1,x , $22, . + brset 1,y , $33, . + bset 1, $11 + bset 1,x, $22 + bset 1,y, $33 + bsr . + bvc . + bvs . + cba + clc + cli + clra + clrb + clr 1 ; extended + clr 1000 + clr 1,x + clr 1,y + clv + cmpa #1 + cmpa 1 + cmpa 1000 + cmpa 1,x + cmpa 1,y + cmpb #1 + cmpb 1 + cmpb 1000 + cmpb 1,x + cmpb 1,y + coma + comb + com 1 ; extended + com 1000 + com 1,x + com 1,y + cpd #1 ; 16 bits + cpd #1000 + cpd 1 + cpd 1000 + cpd 1,x + cpd 1,y + cpx #1 ; 16 bits + cpx #1000 + cpx 1 + cpx 1000 + cpx 1,x + cpx 1,y + cpy #1 ; 16 bits + cpy #1000 + cpy 1 + cpy 1000 + cpy 1,x + cpy 1,y + daa + deca + decb + dec 1 ; extended + dec 1000 + dec 1,x + dec 1,y + des + dex + dey + eora #1 + eora 1 + eora 1000 + eora 1,x + eora 1,y + eorb #1 + eorb 1 + eorb 1000 + eorb 1,x + eorb 1,y + fdiv + idiv + inca + incb + inc 1 ;extended + inc 1000 + inc 1,x + inc 1,y + ins + inx + iny + jmp 1 ;extended + jmp 1000 + jmp 1,x + jmp 1,y + jsr 1 + jsr 1000 + jsr 1,x + jsr 1,y + ldaa #1 + ldaa 1 + ldaa 1000 + ldaa 1,x + ldaa 1,y + ldab #1 + ldab 1 + ldab 1000 + ldab 1,x + ldab 1,y + ldd #1 ;16 bits + ldd #1000 + ldd 1 + ldd 1000 + ldd 1,x + ldd 1,y + lds #1 ;16 bits + lds #1000 + lds 1 + lds 1000 + lds 1,x + lds 1,y + ldx #1 ;16 bits + ldx #1000 + ldx 1 + ldx 1000 + ldx 1,x + ldx 1,y + ldy #1 ;16 bits + ldy #1000 + ldy 1 + ldy 1000 + ldy 1,x + ldy 1,y + lsla + lslb + lsl 1 ;extended + lsl 1000 + lsl 1,x + lsl 1,y + lsld + lsra + lsrb + lsr 1 ;extended + lsr 1000 + lsr 1,x + lsr 1,y + lsrd + mul + nega + negb + neg 1 ;extended + neg 1000 + neg 1,x + neg 1,y + nop + oraa #1 + oraa 1 + oraa 1000 + oraa 1,x + oraa 1,y + orab #1 + orab 1 + orab 1000 + orab 1,x + orab 1,y + psha + pshb + pshx + pshy + pula + pulb + pulx + puly + rola + rolb + rol 1 ;extended + rol 1000 + rol 1,x + rol 1,y + rora + rorb + ror 1 ;extended + ror 1000 + ror 1,x + ror 1,y + rti + rts + sba + sbca #1 + sbca 1 + sbca 1000 + sbca 1,x + sbca 1,y + sbcb #1 + sbcb 1 + sbcb 1000 + sbcb 1,x + sbcb 1,y + sec + sei + sev + staa 1 + staa 1000 + staa 1,x + staa 1,y + stab 1 + stab 1000 + stab 1,x + stab 1,y + std 1 + std 1000 + std 1,x + std 1,y + stop + sts 1 + sts 1000 + sts 1,x + sts 1,y + stx 1 + stx 1000 + stx 1,x + stx 1,y + sty 1 + sty 1000 + sty 1,x + sty 1,y + suba #1 + suba 1 + suba 1000 + suba 1,x + suba 1,y + subb #1 + subb 1 + subb 1000 + subb 1,x + subb 1,y + subd #1 ;extended + subd #1000 + subd 1 + subd 1000 + subd 1,x + subd 1,y + swi + tab + tap + tba + test + tpa + tsta + tstb + tst 1 ;extended + tst 1000 + tst 1,x + tst 1,y + tsx + tsy + txs + tys + wai + xgdx + xgdy + + + + + + + + + + + + + + diff --git a/test/suitef8.asm b/test/suitef8.asm new file mode 100644 index 00000000..0e7a76fa --- /dev/null +++ b/test/suitef8.asm @@ -0,0 +1,279 @@ +; Fairchild F8 test suite for DASM +; 2004 by Thomas Mathys + processor f8 + +TWO = 2 + + org 0 +start + + adc ; 8e + ai $f8 ; 24 f8 + am ; 88 + amd ; 89 + + as start ; c0 + as start+1 ; c1 + as TWO ; c2 + as 3 ; c3 + as 4 ; c4 + as 5 ; c5 + as 2*[1+2] ; c6 + as 7 ; c7 + as (2+2)*2 ; c8 + as 9 ; c9 + as j ; c9 + as $a ; ca + as hu ; ca + as 11 ; cb + as hl ; cb + as s ; cc + as (is) ; cc + as i ; cd + as (is)+ ; cd + as d ; ce + as (is)- ; ce + + asd start ; d0 + asd start+1 ; d1 + asd TWO ; d2 + asd 3 ; d3 + asd 4 ; d4 + asd 5 ; d5 + asd 2*[1+2] ; d6 + asd 7 ; d7 + asd (2+2)*2 ; d8 + asd 9 ; d9 + asd j ; d9 + asd $a ; da + asd hu ; da + asd 11 ; db + asd hl ; db + asd s ; dc + asd (is) ; dc + asd i ; dd + asd (is)+ ; dd + asd d ; de + asd (is)- ; de + + bc . ; 82 ff + bf 12,. ; 9c ff + bm . ; 91 ff + bnc . ; 92 ff + bno . ; 98 ff + bnz . ; 94 ff + bp . ; 81 ff + br . ; 90 ff + br7 . ; 8f ff + bt 5,. ; 85 ff + bz . ; 84 ff + + ci 4096/64-1 ; 25 3f + clr ; 70 + cm ; 8d + com ; 18 + dci TWO ; 2a 00 02 + dci $1234 ; 2a 12 34 + di ; 1a + + ds start ; 30 + ds start+1 ; 31 + ds TWO ; 32 + ds 3 ; 33 + ds 4 ; 34 + ds 5 ; 35 + ds 2*[1+2] ; 36 + ds 7 ; 37 + ds (2+2)*2 ; 38 + ds 9 ; 39 + ds j ; 39 + ds $a ; 3a + ds hu ; 3a + ds 11 ; 3b + ds hl ; 3b + ds s ; 3c + ds (is) ; 3c + ds i ; 3d + ds (is)+ ; 3d + ds d ; 3e + ds (is)- ; 3e + + ei ; 1b + in TWO ; 26 02 + in 16*16-1 ; 26 ff + inc ; 1f + ins 5*3-15 ; a0 + ins 15+start ; af + jmp $1234 ; 29 12 34 + li TWO ; 20 02 + lis %111 ; 77 + lisl (TWO+TWO)*TWO-1 ; 6f + lisu 4 ; 64 + lm ; 16 + lnk ; 19 + + lr start,a ; 50 + lr start+1,a ; 51 + lr TWO,a ; 52 + lr 3,a ; 53 + lr 4,a ; 54 + lr 5,a ; 55 + lr 2*[1+2],a ; 56 + lr 7,a ; 57 + lr (2+2)*2,a ; 58 + lr 9,a ; 59 + lr j,a ; 59 + lr $a,a ; 5a + lr hu,a ; 5a + lr 11,a ; 5b + lr hl,a ; 5b + lr s,a ; 5c + lr (is),a ; 5c + lr i,a ; 5d + lr (is)+,a ; 5d + lr d,a ; 5e + lr (is)-,a ; 5e + + lr a,start ; 40 + lr a,start+1 ; 41 + lr a,TWO ; 42 + lr a,3 ; 43 + lr a,4 ; 44 + lr a,5 ; 45 + lr a,2*[1+2] ; 46 + lr a,7 ; 47 + lr a,(2+2)*2 ; 48 + lr a,9 ; 49 + lr a,j ; 49 + lr a,$a ; 4a + lr a,hu ; 4a + lr a,11 ; 4b + lr a,hl ; 4b + lr a,s ; 4c + lr a,(is) ; 4c + lr a,i ; 4d + lr a,(is)+ ; 4d + lr a,d ; 4e + lr a,(is)- ; 4e + + lr a,ku ; 00 + lr a,kl ; 01 + lr a,qu ; 02 + lr a,ql ; 03 + lr ku,a ; 04 + lr kl,a ; 05 + lr qu,a ; 06 + lr ql,a ; 07 + lr h,dc0 ; 11 + lr h,dc ; 11 + lr q,dc0 ; 0e + lr q,dc ; 0e + lr dc0,h ; 10 + lr dc,h ; 10 + lr dc0,q ; 0f + lr dc,q ; 0f + lr k,pc1 ; 08 + lr k,p ; 08 + lr pc1,k ; 09 + lr p,k ; 09 + lr pc0,q ; 0d + lr p0,q ; 0d + lr a,is ; 0a + lr is,a ; 0b + lr w,j ; 1d + lr w,(TWO+1)*3 ; 1d + lr 9,w ; 1e + lr j,w ; 1e + + ni %10000001 ; 21 81 + nm ; 8a + nop ; 2b + + ns start ; f0 + ns start+1 ; f1 + ns TWO ; f2 + ns 3 ; f3 + ns 4 ; f4 + ns 5 ; f5 + ns 2*[1+2] ; f6 + ns 7 ; f7 + ns (2+2)*2 ; f8 + ns 9 ; f9 + ns j ; f9 + ns $a ; fa + ns hu ; fa + ns 11 ; fb + ns hl ; fb + ns s ; fc + ns (is) ; fc + ns i ; fd + ns (is)+ ; fd + ns d ; fe + ns (is)- ; fe + + oi (TWO+start)*64 ; 22 80 + om ; 8b + + out TWO ; 27 02 + out 16*16-1 ; 27 ff + outs 5*3-15 ; b0 + outs 15+start ; bf + + pi start ; 28 00 00 + pi $1234 ; 28 12 34 + pk ; 0c + pop ; 1c + sl start+1 ; 13 + sl TWO+TWO ; 15 + sr 1 ; 12 + sr 3+1 ; 14 + st ; 17 + xdc ; 2c + xi 64 ; 23 40 + xm ; 8c + + xs start ; e0 + xs start+1 ; e1 + xs TWO ; e2 + xs 3 ; e3 + xs 4 ; e4 + xs 5 ; e5 + xs 2*[1+2] ; e6 + xs 7 ; e7 + xs (2+2)*2 ; e8 + xs 9 ; e9 + xs j ; e9 + xs $a ; ea + xs hu ; ea + xs 11 ; ab + xs hl ; eb + xs s ; ec + xs (is) ; ec + xs i ; ed + xs (is)+ ; ed + xs d ; ee + xs (is)- ; ee + + xs 12 ; ec + xs 13 ; ed + xs 14 ; ee + + dc.b 0 ; 00 + dc.w $1234 ; 12 34 + dc.l $deadbeef ; de ad be ef + + db 0 ; 00 + dw $1234 ; 12 34 + dd $deadbeef ; de ad be ef + + byte 0 ; 00 + word $1234 ; 12 34 + long $deadbeef ; de ad be ef + + .byte 0 ; 00 + .word $1234 ; 12 34 + .long $deadbeef ; de ad be ef + + res.b 4, $33 ; 33 33 33 33 + res.w 2, $1234 ; 12 34 12 34 + res.l 2, $deadbeef ; de ad be ef de ad be ef