; 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 - qABSBOUNDq 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 ; ; example: at the head of a smal 32 source file, include this line: ; | ; | USE "hawk.h" ; | ; --------------------- ; definitions of register symbols 0 to 15 EXT qREGISTERq ; relocation base for registers, ; defined so that register symbols R0 = qREGISTERq+0 ; cannot be confused with small R1 = qREGISTERq+1 ; integers, thus tightening up the R2 = qREGISTERq+2 ; assembly-time type checking R3 = qREGISTERq+3 ; offered by this macro package R4 = qREGISTERq+4 R5 = qREGISTERq+5 R6 = qREGISTERq+6 R7 = qREGISTERq+7 R8 = qREGISTERq+8 R9 = qREGISTERq+9 RA = qREGISTERq+10 ; hex names RB = qREGISTERq+11 RC = qREGISTERq+12 RD = qREGISTERq+13 RE = qREGISTERq+14 RF = qREGISTERq+15 R10 = qREGISTERq+10 ; decimal names also R11 = qREGISTERq+11 R12 = qREGISTERq+12 R13 = qREGISTERq+13 R14 = qREGISTERq+14 R15 = qREGISTERq+15 PC = R0 ; --------------------- ; definitions of special CPU registers ; each distinct group of special registers has its own relocation ; base so that these symbols become illegal outside of contexts ; where that register group is used EXT qCPUCONTROLq PSW = qCPUCONTROLq+0 TPC = qCPUCONTROLq+1 TMA = qCPUCONTROLq+2 TSV = qCPUCONTROLq+3 CYC = qCPUCONTROLq+8 EXT qCOPROCREGq COSTAT = qCOPROCREGq+0 EXT qADJUSTq BCD = qADJUSTq+2 EX3 = qADJUSTq+3 CMSB = qADJUSTq+4 SSQ = qADJUSTq+5 PLUS1 = qADJUSTq+8 PLUS2 = qADJUSTq+9 PLUS4 = qADJUSTq+10 PLUS8 = qADJUSTq+11 PLUS16 = qADJUSTq+12 PLUS32 = qADJUSTq+13 PLUS64 = qADJUSTq+14 PLUS128 = qADJUSTq+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 qREGCHECKq =x IF LEN(x)>0 IF ~(TYP(x) = TYP(qREGISTERq)) ERROR x must be a register ENDIF ELSE ERROR missing register ENDIF ENDMAC MACRO qSPECCHECKq =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 qBOUNDq =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 qABSBOUNDq =x,=min,=max IF LEN(x)>0 IF (TYP(x) = 0) qBOUNDq x,min,max ELSEIF (TYP(x) = TYP(qREGISTERq)) ERROR x must be an absolute constant ENDIF ELSE ERROR missing constant ENDIF ENDMAC MACRO qNZREGq =x IF LEN(x)>0 IF (TYP(x) = TYP(qREGISTERq)) IF (x = R0) ERROR R0 not allowed ENDIF ENDIF ENDIF ENDMAC MACRO qPCRELq =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 qMEMREFq =op,=dst,=x,=const IF LEN(const)>0 qREGCHECKq dst qREGCHECKq x qABSBOUNDq const,-#8000,#7FFF B (op >> 8) ! (dst-qREGISTERq) B (op & #FF) ! (x-qREGISTERq) H const ELSE qREGCHECKq dst qPCRELq x B (op >> 8) ! (dst-qREGISTERq) B (op & #FF) H x - (.+2) ENDIF ENDMAC MACRO qBRANCHq =op,=const qPCRELq const qCONSTq = const - (.+2) >> 1 qBOUNDq qCONSTq,-128,+127 IF LEN(const)>0 IF qCONSTq = -1 ERROR self branch discouraged ENDIF ENDIF B (op >> 8) B (qCONSTq & #FF) ENDMAC MACRO qONE5REGq =op,=dst,=x qREGCHECKq dst B (op >> 8) ! (dst-qREGISTERq) B (op & #FF) ! (x & #F) ENDMAC MACRO qTWOREGq =op,=dst,=x qREGCHECKq dst qREGCHECKq x B (op >> 8) ! (dst-qREGISTERq) B (op & #FF) ! (x-qREGISTERq) ENDMAC MACRO qSPECREGq =op,=dst,=x,=base qREGCHECKq 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-qREGISTERq) B (op & #FF) ! (x-base) ENDMAC MACRO qTWO5REGq =op,=dst,=s1,=x qREGCHECKq dst qREGCHECKq s1 qABSBOUNDq x,1,16 B (op >> 8) ! (dst-qREGISTERq) B (s1-qREGISTERq << 4) ! (x & #F) ENDMAC MACRO qTHREEREGq =op,=dst,=s1,=s2 qREGCHECKq dst qREGCHECKq s1 qREGCHECKq s2 B (op >> 8) ! (dst-qREGISTERq) B (s1-qREGISTERq << 4) ! (s2-qREGISTERq) ENDMAC ; --------------------- ; macros for all HAWK opcodes MACRO MOVE =dst,=x qNZREGq dst qTWOREGq #F0F0,dst,x ENDMAC MACRO MOVECC =dst,=x qTWOREGq #F0E0,dst,x ENDMAC MACRO LOADS =dst,=x qTWOREGq #F0D0,dst,x ENDMAC MACRO LOADSCC =dst,=x qTWOREGq #F0C0,dst,x ENDMAC MACRO JSRS =dst,=x qTWOREGq #F0B0,dst,x ENDMAC MACRO STORES =dst,=x qNZREGq x qTWOREGq #F0A0,dst,x ENDMAC MACRO LOADL =dst,=x qNZREGq x qTWOREGq #F090,dst,x ENDMAC MACRO STOREC =dst,=x qNZREGq x qTWOREGq #F080,dst,x ENDMAC MACRO LEA =dst,=x,=const qNZREGq dst qMEMREFq #F070,dst,x,const ENDMAC MACRO LEACC =dst,=x,=const qMEMREFq #F060,dst,x,const ENDMAC MACRO LOAD =dst,=x,=const qMEMREFq #F050,dst,x,const ENDMAC MACRO LOADCC =dst,=x,=const qMEMREFq #F040,dst,x,const ENDMAC MACRO JSR =dst,=x,=const qMEMREFq #F030,dst,x,const ENDMAC MACRO STORE =dst,=x,=const qMEMREFq #F020,dst,x,const ENDMAC MACRO LIL =dst,=const qABSBOUNDq const,-#800000,#7FFFFF B #E0 ! (dst-qREGISTERq) T const ENDMAC MACRO LIS =dst,=const qNZREGq dst qABSBOUNDq const,-#80,#7F B #D0 ! (dst-qREGISTERq) B const ENDMAC MACRO ORIS =dst,=const qNZREGq dst qABSBOUNDq const,#00,#FF B #C0 ! (dst-qREGISTERq) B const ENDMAC MACRO MOVESL =dst,=s1,=s2 qNZREGq s1 qTWO5REGq #B000,dst,s1,s2 ENDMAC MACRO ADDSL =dst,=s1,=s2 qNZREGq dst qTWO5REGq #A000,dst,s1,s2 ENDMAC MACRO ADDSR =dst,=s1,=s2 qTWO5REGq #9000,dst,s1,s2 ENDMAC MACRO ADDSRU =dst,=s1,=s2 qTWO5REGq #8000,dst,s1,s2 ENDMAC MACRO STUFFB =dst,=s1,=s2 qNZREGq dst qTHREEREGq #7000,dst,s1,s2 ENDMAC MACRO STUFFH =dst,=s1,=s2 qNZREGq dst qTHREEREGq #6000,dst,s1,s2 ENDMAC MACRO EXTB =dst,=s1,=s2 qNZREGq s1 qTHREEREGq #5000,dst,s1,s2 ENDMAC MACRO EXTH =dst,=s1,=s2 qNZREGq s1 qTHREEREGq #4000,dst,s1,s2 ENDMAC MACRO ADD =dst,=s1,=s2 qNZREGq s1 qNZREGq s2 qTHREEREGq #3000,dst,s1,s2 ENDMAC MACRO SUB =dst,=s1,=s2 qNZREGq s2 qTHREEREGq #2000,dst,s1,s2 ENDMAC MACRO TRUNC =dst,=src qNZREGq dst qBOUNDq src,1,16 qONE5REGq #10F0,dst,src ENDMAC MACRO SXT =dst,=src qNZREGq dst qBOUNDq src,1,16 qONE5REGq #10E0,dst,src ENDMAC MACRO BTRUNC =dst,=src qNZREGq dst qBOUNDq src,1,16 qONE5REGq #10D0,dst,src ENDMAC MACRO ADDSI =dst,=src qNZREGq dst IF LEN(src)>0 IF (src = 0) ERROR constant 0 not allowed ENDIF ENDIF qABSBOUNDq src,-8,+8 IF src = +8 qONE5REGq #10C0,dst,0 ELSE qONE5REGq #10C0,dst,src ENDIF ENDMAC MACRO AND =dst,=src qNZREGq src qNZREGq dst qTWOREGq #10B0,dst,src ENDMAC MACRO OR =dst,=src qNZREGq src qNZREGq dst qTWOREGq #10A0,dst,src ENDMAC MACRO EQU =dst,=src qNZREGq dst qTWOREGq #1090,dst,src ENDMAC MACRO ADDC =dst,=src qTWOREGq #1070,dst,src ENDMAC MACRO SUBB =dst,=src qTWOREGq #1060,dst,src ENDMAC MACRO ADJUST =dst,=src qNZREGq dst qSPECREGq #1050,dst,src,qADJUSTq ENDMAC MACRO PLUS =dst,=src qNZREGq dst qTWOREGq #1040,dst,src ENDMAC MACRO COGET =dst,=src qSPECREGq #1030,dst,src,qCOPROCREGq ENDMAC MACRO COSET =dst,=src qSPECREGq #1020,dst,src,qCOPROCREGq ENDMAC MACRO CPUGET =dst,=src qSPECREGq #1010,dst,src,qCPUCONTROLq ENDMAC MACRO CPUSET =dst,=src qSPECREGq #1000,dst,src,qCPUCONTROLq ENDMAC MACRO BGTU =const qBRANCHq #0F00,const ENDMAC MACRO BGT =const qBRANCHq #0E00,const ENDMAC MACRO BGE =const qBRANCHq #0D00,const ENDMAC MACRO BCR =const qBRANCHq #0C00,const ENDMAC MACRO BVR =const qBRANCHq #0B00,const ENDMAC MACRO BZR =const qBRANCHq #0A00,const ENDMAC MACRO BNR =const qBRANCHq #0900,const ENDMAC MACRO BLEU =const qBRANCHq #0700,const ENDMAC MACRO BLE =const qBRANCHq #0600,const ENDMAC MACRO BLT =const qBRANCHq #0500,const ENDMAC MACRO BCS =const qBRANCHq #0400,const ENDMAC MACRO BVS =const qBRANCHq #0300,const ENDMAC MACRO BZS =const qBRANCHq #0200,const ENDMAC MACRO BNS =const qBRANCHq #0100,const ENDMAC MACRO BR =const qBRANCHq #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 qBBSq = #0400 qBBRq = #0C00 ELSE IF s2<31 MOVESL R0,s1,(31-s2) ELSE MOVECC R0,s1 ENDIF qBBSq = #0100 qBBRq = #0900 ENDIF ENDMAC MACRO BBS =const qBRANCHq qBBSq,const ENDMAC MACRO BBR =const qBRANCHq qBBRq,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 R0,TPC ENDMAC ; --------------------- ; macros for compound instructions MACRO LIW =dst, =const LIL dst, const >> 8 ORIS dst, const & #FF ENDMAC