; hawk.h -- standard Hawk definitions and macros ; language: SMAL32 assembly language, intended as an include file ; author: Douglas W. Jones ; date: June 2, 1997 ; revised: Feb. 27, 2002 - replace BCDGET with EX3ADJ instruction ; revised: Mar. 1, 2002 - add SSQADJ ; revised: Mar. 13, 2002 - add BTRUNC ; revised: July 18, 2002 - replace *ADJ with ADJUST, recode B* branches ; revised: July 22, 2002 - add MOVESL, BITTST improve error msgs ; revised: July 25, 2002 - recode Fxxx opcodes, add LOADL, STOREC ; revised: Jan 20, 2005 - delete old SXB,SXH opcodes ; revised: Aug. 13, 2008 - reverse IR byte order, add COGET, COSET ; revised: Nov. 20, 2008 - fix coprocessor support ; revised: Nov. 27, 2010 - fix BITTST ; revised: Jun. 7, 2011 - signed shift vs unsigned shift ; revised: May. 22, 2014 - _ABSBOUND_ added for better error checks ; revised: Jun. 18, 2014 - ADJUST PLUSx, PLUS instructions ; revised: Jul. 15, 2014 - bug in ADDSI R,+8 fixed ; revised: Dec. 16, 2019 - allow PC as dst for LOAD, LOADS, LIL ; revised: Jan. 2, 2024 - improve error messages ; revised: May. 22, 2024 - use =: for immutable names, _ for private names ; ; example: at the head of a smal 32 source file, include this line: ; | ; | USE "hawk.h" ; | ; --------------------- ; Each distinct group of registers has its own relocation base so ; that register names to create a distinct data type for each register ; group. This allows a useful degree of type checking. The actual ; values of these relocation bases are never given and do not matter; ; that is, no corresponding INT directive is ever needed. ; definitions of register symbols 0 to 15 EXT _REGISTER_ R0 =: _REGISTER_+0 R1 =: _REGISTER_+1 R2 =: _REGISTER_+2 R3 =: _REGISTER_+3 R4 =: _REGISTER_+4 R5 =: _REGISTER_+5 R6 =: _REGISTER_+6 R7 =: _REGISTER_+7 R8 =: _REGISTER_+8 R9 =: _REGISTER_+9 RA =: _REGISTER_+10 ; hex names RB =: _REGISTER_+11 RC =: _REGISTER_+12 RD =: _REGISTER_+13 RE =: _REGISTER_+14 RF =: _REGISTER_+15 R10 =: _REGISTER_+10 ; decimal names also R11 =: _REGISTER_+11 R12 =: _REGISTER_+12 R13 =: _REGISTER_+13 R14 =: _REGISTER_+14 R15 =: _REGISTER_+15 PC =: R0 ; definitions of special CPU registers EXT _CPUCONTROL_ PSW =: _CPUCONTROL_+0 TPC =: _CPUCONTROL_+1 TMA =: _CPUCONTROL_+2 TSV =: _CPUCONTROL_+3 CYC =: _CPUCONTROL_+8 EXT _COPROCREG_ COSTAT =: _COPROCREG_+0 EXT _ADJUST_ BCD =: _ADJUST_+2 EX3 =: _ADJUST_+3 CMSB =: _ADJUST_+4 SSQ =: _ADJUST_+5 PLUS1 =: _ADJUST_+8 PLUS2 =: _ADJUST_+9 PLUS4 =: _ADJUST_+10 PLUS8 =: _ADJUST_+11 PLUS16 =: _ADJUST_+12 PLUS32 =: _ADJUST_+13 PLUS64 =: _ADJUST_+14 PLUS128 =: _ADJUST_+15 ; --------------------- ; service macros MACRO ALIGN =x IF x > 1 IF (x & 1) = 1 ERROR odd parameter to ALIGN ELSE ALIGN (x>>1) .=.+(ABS(.)&(x>>1)) ENDIF ENDIF ENDMAC ; --------------------- ; internal macros for checking field constraints MACRO _REGCHECK_ =x IF LEN(x)>0 IF ~(TYP(x) = TYP(_REGISTER_)) ERROR x must be a register ENDIF ELSE ERROR missing register ENDIF ENDMAC MACRO _SPECCHECK_ =x,=base IF LEN(x)>0 IF ~(TYP(x) = TYP(base)) ERROR x must be a base ENDIF ELSE ERROR missing special register ENDIF ENDMAC MACRO _BOUND_ =x,=min,=max IF LEN(x)>0 IF (TYP(x) = TYP(min)) IF (x > max) ERROR x > max out of bounds ELSEIF (x < min) ERROR x < min out of bounds ENDIF ENDIF ENDIF ENDMAC MACRO _ABSBOUND_ =x,=min,=max IF LEN(x)>0 IF (TYP(x) = 0) _BOUND_ x,min,max ELSEIF (TYP(x) = TYP(_REGISTER_)) ERROR x must be an absolute constant ENDIF ELSE ERROR missing constant ENDIF ENDMAC MACRO _NZREG_ =x IF LEN(x)>0 IF (TYP(x) = TYP(_REGISTER_)) IF (x = R0) ERROR R0 not allowed ENDIF ENDIF ENDIF ENDMAC MACRO _PCREL_ =x IF LEN(x)>0 IF ~(TYP(x) = TYP(.)) ERROR illegal PC-relative address ENDIF ELSE ERROR PC-relative address expected ENDIF ENDMAC ; --------------------- ; internal macros for common instruction formats MACRO _MEMREF_ =op,=dst,=x,=const IF LEN(const)>0 _REGCHECK_ dst _REGCHECK_ x _ABSBOUND_ const,-#8000,#7FFF B (op >> 8) ! (dst-_REGISTER_) B (op & #FF) ! (x-_REGISTER_) H const ELSE _REGCHECK_ dst _PCREL_ x B (op >> 8) ! (dst-_REGISTER_) B (op & #FF) H x - (.+2) ENDIF ENDMAC MACRO _BRANCH_ =op,=const _PCREL_ const _CONST_ = const - (.+2) >> 1 _BOUND_ _CONST_,-128,+127 IF LEN(const)>0 IF _CONST_ = -1 ERROR self branch discouraged ENDIF ENDIF B (op >> 8) B (_CONST_ & #FF) ENDMAC MACRO _ONE5REG_ =op,=dst,=x _REGCHECK_ dst B (op >> 8) ! (dst-_REGISTER_) B (op & #FF) ! (x & #F) ENDMAC MACRO _TWOREG_ =op,=dst,=x _REGCHECK_ dst _REGCHECK_ x B (op >> 8) ! (dst-_REGISTER_) B (op & #FF) ! (x-_REGISTER_) ENDMAC MACRO _SPECREG_ =op,=dst,=x,=base _REGCHECK_ dst IF LEN(x)>0 IF ~(TYP(x) = TYP(base)) ERROR x must be a base ENDIF ELSE ERROR a base expected ENDIF B (op >> 8) ! (dst-_REGISTER_) B (op & #FF) ! (x-base) ENDMAC MACRO _TWO5REG_ =op,=dst,=s1,=x _REGCHECK_ dst _REGCHECK_ s1 _ABSBOUND_ x,1,16 B (op >> 8) ! (dst-_REGISTER_) B (s1-_REGISTER_ << 4) ! (x & #F) ENDMAC MACRO _THREEREG_ =op,=dst,=s1,=s2 _REGCHECK_ dst _REGCHECK_ s1 _REGCHECK_ s2 B (op >> 8) ! (dst-_REGISTER_) B (s1-_REGISTER_ << 4) ! (s2-_REGISTER_) ENDMAC ; --------------------- ; macros for all HAWK opcodes MACRO MOVE =dst,=x _NZREG_ dst _TWOREG_ #F0F0,dst,x ENDMAC MACRO MOVECC =dst,=x _TWOREG_ #F0E0,dst,x ENDMAC MACRO LOADS =dst,=x _TWOREG_ #F0D0,dst,x ENDMAC MACRO LOADSCC =dst,=x _TWOREG_ #F0C0,dst,x ENDMAC MACRO JSRS =dst,=x _TWOREG_ #F0B0,dst,x ENDMAC MACRO STORES =dst,=x _NZREG_ x _TWOREG_ #F0A0,dst,x ENDMAC MACRO LOADL =dst,=x _NZREG_ x _TWOREG_ #F090,dst,x ENDMAC MACRO STOREC =dst,=x _NZREG_ x _TWOREG_ #F080,dst,x ENDMAC MACRO LEA =dst,=x,=const _NZREG_ dst _MEMREF_ #F070,dst,x,const ENDMAC MACRO LEACC =dst,=x,=const _MEMREF_ #F060,dst,x,const ENDMAC MACRO LOAD =dst,=x,=const _MEMREF_ #F050,dst,x,const ENDMAC MACRO LOADCC =dst,=x,=const _MEMREF_ #F040,dst,x,const ENDMAC MACRO JSR =dst,=x,=const _MEMREF_ #F030,dst,x,const ENDMAC MACRO STORE =dst,=x,=const _MEMREF_ #F020,dst,x,const ENDMAC MACRO LIL =dst,=const _ABSBOUND_ const,-#800000,#7FFFFF B #E0 ! (dst-_REGISTER_) T const ENDMAC MACRO LIS =dst,=const _NZREG_ dst _ABSBOUND_ const,-#80,#7F B #D0 ! (dst-_REGISTER_) B const ENDMAC MACRO ORIS =dst,=const _NZREG_ dst _ABSBOUND_ const,#00,#FF B #C0 ! (dst-_REGISTER_) B const ENDMAC MACRO MOVESL =dst,=s1,=s2 _NZREG_ s1 _TWO5REG_ #B000,dst,s1,s2 ENDMAC MACRO ADDSL =dst,=s1,=s2 _NZREG_ dst _TWO5REG_ #A000,dst,s1,s2 ENDMAC MACRO ADDSR =dst,=s1,=s2 _TWO5REG_ #9000,dst,s1,s2 ENDMAC MACRO ADDSRU =dst,=s1,=s2 _TWO5REG_ #8000,dst,s1,s2 ENDMAC MACRO STUFFB =dst,=s1,=s2 _NZREG_ dst _THREEREG_ #7000,dst,s1,s2 ENDMAC MACRO STUFFH =dst,=s1,=s2 _NZREG_ dst _THREEREG_ #6000,dst,s1,s2 ENDMAC MACRO EXTB =dst,=s1,=s2 _NZREG_ s1 _THREEREG_ #5000,dst,s1,s2 ENDMAC MACRO EXTH =dst,=s1,=s2 _NZREG_ s1 _THREEREG_ #4000,dst,s1,s2 ENDMAC MACRO ADD =dst,=s1,=s2 _NZREG_ s1 _NZREG_ s2 _THREEREG_ #3000,dst,s1,s2 ENDMAC MACRO SUB =dst,=s1,=s2 _NZREG_ s2 _THREEREG_ #2000,dst,s1,s2 ENDMAC MACRO TRUNC =dst,=src _NZREG_ dst _BOUND_ src,1,16 _ONE5REG_ #10F0,dst,src ENDMAC MACRO SXT =dst,=src _NZREG_ dst _BOUND_ src,1,16 _ONE5REG_ #10E0,dst,src ENDMAC MACRO BTRUNC =dst,=src _NZREG_ dst _BOUND_ src,1,16 _ONE5REG_ #10D0,dst,src ENDMAC MACRO ADDSI =dst,=src _NZREG_ dst IF LEN(src)>0 IF (src = 0) ERROR constant 0 not allowed ENDIF ENDIF _ABSBOUND_ src,-8,+8 IF src = +8 _ONE5REG_ #10C0,dst,0 ELSE _ONE5REG_ #10C0,dst,src ENDIF ENDMAC MACRO AND =dst,=src _NZREG_ src _NZREG_ dst _TWOREG_ #10B0,dst,src ENDMAC MACRO OR =dst,=src _NZREG_ src _NZREG_ dst _TWOREG_ #10A0,dst,src ENDMAC MACRO EQU =dst,=src _NZREG_ dst _TWOREG_ #1090,dst,src ENDMAC MACRO ADDC =dst,=src _TWOREG_ #1070,dst,src ENDMAC MACRO SUBB =dst,=src _TWOREG_ #1060,dst,src ENDMAC MACRO ADJUST =dst,=src _NZREG_ dst _SPECREG_ #1050,dst,src,_ADJUST_ ENDMAC MACRO PLUS =dst,=src _NZREG_ dst _TWOREG_ #1040,dst,src ENDMAC MACRO COGET =dst,=src _SPECREG_ #1030,dst,src,_COPROCREG_ ENDMAC MACRO COSET =dst,=src _SPECREG_ #1020,dst,src,_COPROCREG_ ENDMAC MACRO CPUGET =dst,=src _SPECREG_ #1010,dst,src,_CPUCONTROL_ ENDMAC MACRO CPUSET =dst,=src _SPECREG_ #1000,dst,src,_CPUCONTROL_ ENDMAC MACRO BGTU =const _BRANCH_ #0F00,const ENDMAC MACRO BGT =const _BRANCH_ #0E00,const ENDMAC MACRO BGE =const _BRANCH_ #0D00,const ENDMAC MACRO BCR =const _BRANCH_ #0C00,const ENDMAC MACRO BVR =const _BRANCH_ #0B00,const ENDMAC MACRO BZR =const _BRANCH_ #0A00,const ENDMAC MACRO BNR =const _BRANCH_ #0900,const ENDMAC MACRO BLEU =const _BRANCH_ #0700,const ENDMAC MACRO BLE =const _BRANCH_ #0600,const ENDMAC MACRO BLT =const _BRANCH_ #0500,const ENDMAC MACRO BCS =const _BRANCH_ #0400,const ENDMAC MACRO BVS =const _BRANCH_ #0300,const ENDMAC MACRO BZS =const _BRANCH_ #0200,const ENDMAC MACRO BNS =const _BRANCH_ #0100,const ENDMAC MACRO BR =const _BRANCH_ #0000,const ENDMAC ; --------------------- ; macros for derived instructions MACRO TEST =x,=disp LOADCC R0,x,disp ENDMAC MACRO ADDI =dst,=src,=const LEACC dst,src,const ENDMAC MACRO CMPI =x,=disp LEACC R0,x,-disp ENDMAC MACRO JUMP =x,=disp IF LEN(disp)>0 JSR R0,x,disp ELSE JSR R0,x ENDIF ENDMAC MACRO TESTS =x LOADSCC R0,x ENDMAC MACRO TESTR =x MOVECC R0,x ENDMAC MACRO JUMPS =x JSRS R0,x ENDMAC MACRO CLR =x LIS x,0 ENDMAC MACRO BNE =x BZR x ENDMAC MACRO BLTU =x BCR x ENDMAC MACRO BEQ =x BZS x ENDMAC MACRO BGEU =x BCS x ENDMAC MACRO NOP =x BR .+2 ENDMAC MACRO SL =dst,=src ADDSL dst,R0,src ENDMAC MACRO SR =dst,=src ADDSR dst,R0,src ENDMAC MACRO SRU =dst,=src ADDSRU dst,R0,src ENDMAC MACRO BITTST =s1,=s2 IF s2<16 ADDSR R0,s1,s2+1 _BBS_ = #0400 _BBR_ = #0C00 ELSE IF s2<31 MOVESL R0,s1,(31-s2) ELSE MOVECC R0,s1 ENDIF _BBS_ = #0100 _BBR_ = #0900 ENDIF ENDMAC MACRO BBS =const _BRANCH_ _BBS_,const ENDMAC MACRO BBR =const _BRANCH_ _BBR_,const ENDMAC MACRO CMP =s1,=s2 SUB R0,s1,s2 ENDMAC MACRO NEG =dst,=src SUB dst,R0,src ENDMAC MACRO NOT =dst EQU dst,R0 ENDMAC MACRO ROL =dst ADDC dst,dst ENDMAC MACRO RTT =dst CPUGET PC,TPC ENDMAC ; --------------------- ; macros for compound instructions MACRO LIW =dst, =const LIL dst, const >> 8 ORIS dst, const & #FF ENDMAC