URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 13 to Rev 12
- ↔ Reverse comparison
Rev 13 → Rev 12
/zipcpu/trunk/sw/zasm/asmdata.cpp
File deleted
/zipcpu/trunk/sw/zasm/zasm.l
File deleted
/zipcpu/trunk/sw/zasm/asmdata.h
File deleted
/zipcpu/trunk/sw/zasm/sys.i
File deleted
/zipcpu/trunk/sw/zasm/zasm.y
File deleted
/zipcpu/trunk/sw/zasm/zpp.l
File deleted
/zipcpu/trunk/sw/zasm/zparser.cpp
4,14 → 4,7
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// |
// Purpose: This file is really mis-named. At one time it was going to |
// be the parser for the Zip Assembler, zasm. Since then, I |
// discovered Flex and Bison and have written a parser using |
// those tools. The true parser may therefore be found in zasm.y. |
// This file, however, still contains some very valuable tools. |
// In particular, all of the routines used to build instructions |
// from the appropriate fields are kept in this file. For example, |
// op_noop() returns the instruction code for a NOOP instruction. |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
52,6 → 45,359
|
typedef ZPARSER::ZIPI ZIPI; // A Zip Instruction (i.e. uint32) |
|
bool ZPARSER::iscomment(const char *line) const { |
const char *sp = line; |
do { |
if (*sp == '\0') |
return true; |
else if (*sp == ';') |
return true; |
else if (*sp == '#') |
return true; |
else if (*sp == '\n') |
return true; |
else if (*sp == '\r') |
return true; |
else if ((*sp == '/')&&(sp[1] == '/')) |
return true; |
else if (!isspace(*sp)) |
return false; |
} while(*sp++); |
|
return true; |
} |
|
bool ZPARSER::islabel(const char *line) const { |
const char *sp = line; |
if (isspace(*line)) |
return false; |
if (!isalpha(*line)) |
return false; |
while((isalpha(*sp))||(isdigit(*sp))||(*sp=='_')) |
sp++; |
if (*sp != ':') |
return false; |
sp++; |
return iscomment(sp); |
} |
|
bool ZPARSER::parse_op(const char *line, ZPARSER::ZIPA pc, |
ZPARSER::ZIPI &ins, const unsigned lineno) const { |
const char *sp = line; |
char cpy[128], *cp = cpy, *point, *dollar, *plus, *comma, *paren, |
*opc, *opb, *opa; |
ZPARSER::ZIPREG ra = ZPARSER::ZIP_Rnone, rb = ZPARSER::ZIP_Rnone; |
ZIPCOND cnd = ZIPC_ALWAYS; |
ZIPIMM imm = 0; |
bool valid = true; |
|
if (!isspace(*sp)) |
return false; |
|
while(isspace(*sp)) |
sp++; |
// Remove comments from our local copy |
for(unsigned int i=0; i<sizeof(cpy); i++) { |
if (*sp == '\0') |
break; |
else if (*sp == ';') |
break; |
else if (*sp == '#') |
break; |
else if (*sp == '\n') |
break; |
else if (*sp == '\r') |
break; |
else if ((*sp == '/')&&(sp[1] == '/')) |
break; |
*cp++ = *sp++; |
} if (cp-cpy >= (int)sizeof(cpy)) |
return false; |
*cp = '\0'; |
point = strchr(cpy, '.'); |
comma = strchr(cpy, ','); |
plus = strchr(cpy, '+'); |
dollar= strchr(cpy, '$'); |
paren = strchr(cpy, '('); |
if (point) *point++ = '\0'; |
if (comma) *comma++ = '\0'; |
if (plus) *plus++ = '\0'; |
if (dollar) *dollar++ = '\0'; |
// if (paren) *paren++ = '\0'; |
cp = cpy; |
while(isalpha(*cp)) |
cp++; |
opc = cpy; |
if ((*cp == '\0')&&(point == NULL)) |
cp[1] = '\0'; |
*cp = '\0'; |
|
if ((point)&&(strncasecmp("DAT",point,3)!=0)) { |
cp = point; |
while(isalpha(*cp)) |
cp++; |
if (*cp == '\0') |
cp[1] = '\0'; |
*cp = '\0'; |
|
for(int i=1; i<8; i++) { |
if (strcasecmp(&zop_ccstr[i][1], point)==0) { |
cnd = (ZIPCOND)i; |
break; |
} |
} if (cnd == ZIPC_ALWAYS) { |
printf("ERR: Unrecognized condition, %s\n", point); |
valid = false; |
} |
} |
|
cp++; |
while(isspace(*cp)) |
cp++; |
opb = cp; |
opa = comma; |
|
if (paren) { |
opb = paren+1; |
if ((comma)&&(opb > comma)) |
opa = cp; |
} else if (plus) |
opb = plus; |
|
if (dollar) { |
// Figure out the base |
{ |
char *ip = dollar, mxd = 0; |
if ((*ip == '0')&&(toupper(ip[1])=='X')) |
imm = strtoul(dollar, NULL, 16); |
else { |
bool neg = false; |
if (*ip == '-') { |
neg = true; |
ip++; |
dollar++; |
} |
while(isdigit(*ip)||((toupper(*ip)>='A')&&(toupper(*ip)<='F'))) { |
if (isalpha(*ip)) |
mxd = (*ip-'a')+10; |
else |
mxd = (*ip-'0'); |
ip++; |
} |
|
if ((mxd <= 1)&&(*ip=='d')) |
imm = strtoul(dollar, NULL, 2); |
else if ((mxd <= 7)&&((*dollar == '0')||(toupper(*ip)=='O'))) |
imm = strtoul(dollar, NULL, 8); |
else if ((mxd <= 15)&&(toupper(*ip)=='H')) |
imm = strtoul(dollar, NULL, 16); |
else if ((toupper(*ip)=='D')||(*ip == '+')||(isspace(*ip))||(*ip == '(')||(*ip == '\0')) |
imm = atoi(dollar); |
else { |
printf("Cannot parse immediate, %s\n", dollar); |
printf("Assuming you meant %d\n", atoi(dollar)); |
imm = atoi(dollar); |
} |
|
if (neg) |
imm = -imm; |
} |
} |
} else |
imm = 0; |
|
if (*opb) for(int i=31; i>=0; i--) { |
// printf("%s Checking for match to opB: \'%s\' to %s", opc, opb, zop_regstr[i]); |
if (NULL != strcasestr(opb, zop_regstr[i])) { |
// printf(" --- Match\n"); |
rb = (ZIPREG)i; |
break; |
} // else printf(" -- nope\n"); |
} if (opa) for(int i=31; i>=0; i--) { |
// printf("%s Checking for match to opA: ,%s to %s", opc, opa, zop_regstr[i]); |
if (NULL != strcasestr(opa, zop_regstr[i])) { |
ra = (ZIPREG)i; |
// printf(" --- Match\n"); |
break; |
} // else printf(" -- nope\n"); |
} |
|
if (strcasecmp("MOV",opc)!=0) { |
// Only move instructions can reference user regs |
if ((ra != ZIP_Rnone)&&(ra >= ZIP_uR0)) |
valid = false; |
if ((rb != ZIP_Rnone)&&(rb >= ZIP_uR0)) |
valid = false; |
if (!valid) |
printf("ERR: Only Mov can specify user regs\n"); |
} |
|
if ((!*opc)&&(strncasecmp("DAT",point,3)==0)) { |
ins = imm; |
valid = true; |
} else if (strcasecmp("CMP",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_cmp(cnd, imm, rb, ra); |
else ins = op_cmp(cnd, imm, ra); |
} else if (strcasecmp("TST",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_tst(cnd, imm, rb, ra); |
else if (!dollar) |
ins = op_tst(cnd, ra); |
else |
ins = op_tst(cnd, imm, ra); |
} else if (strcasecmp("MOV",opc)==0) { |
if ((rb != ZIP_Rnone)&&(ra != ZIP_Rnone)) |
ins = op_mov(cnd, imm, rb, ra); |
else { printf("ERR MOV, ra = %d, rb = %d, imm = %d, cnd = %d\nLine was: %s", (int)ra, (int)rb, (int)imm, (int)cnd, line); valid = false; } |
} else if (strcasecmp("LDI",opc)==0) { |
if ((rb == ZIP_Rnone)&&(cnd == ZIPC_ALWAYS)) |
ins = op_ldi(imm, ra); |
else valid = false; |
} else if (strcasecmp("trap",opc)==0) { |
if ((rb == ZIP_Rnone)&&(rb == ZIP_Rnone)) |
ins = op_trap(cnd, imm); |
else |
valid = false; |
} else if (strcasecmp("CLR",opc)==0) { |
if ((ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS)) |
ins = op_clr(rb); // Good |
else valid = false; |
} else if ((strcasecmp("NOOP",opc)==0)||(strcasecmp("NOP",opc)==0)) { |
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS)) |
ins = op_noop(); |
else { printf("ERR: NOP, ra=%d, rb=%d, dollar = %s\n", |
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; } |
} else if ((strcasecmp("BREAK",opc)==0)||(strcasecmp("BRK",opc)==0)) { |
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS)) |
ins = op_break(); |
else { printf("ERR: BRK, ra=%d, rb=%d, dollar = %s\n", |
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; } |
} else if ((strcasecmp("LDIHI",opc)==0)||(strcasecmp("LODIHI",opc)==0)) { |
if ((dollar)&&(ra != ZIP_Rnone)) |
ins = op_ldihi(cnd, imm, ra); |
else valid = false; |
} else if ((strcasecmp("LDILO",opc)==0)||(strcasecmp("LODILO",opc)==0)){ |
if ((dollar)&&(ra != ZIP_Rnone)) |
ins = op_ldilo(cnd, imm, ra); |
else valid = false; |
} else if ((strcasecmp("LOD",opc)==0)||(strcasecmp("LOAD",opc)==0)) { |
if (rb != ZIP_Rnone) |
ins = op_lod(cnd,imm,rb,ra); |
else ins = op_lod(cnd,imm,ra); |
} else if ((strcasecmp("STO",opc)==0)||(strcasecmp("STOR",opc)==0)) { |
// printf("STO: Imm = %d, RA = %d, RB = %d\n", imm, ra, rb); |
if (rb != ZIP_Rnone) |
ins = op_sto(cnd,ra,imm,rb); |
else ins = op_sto(cnd,ra,imm); |
} else if (strcasecmp("SUB",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_sub(cnd,imm,rb,ra); |
else ins = op_sub(cnd,imm,ra); |
} else if (strcasecmp("AND",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_and(cnd,imm,rb,ra); |
else ins = op_and(cnd,imm,ra); |
} else if (strcasecmp("ADD",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_add(cnd,imm,rb,ra); |
else ins = op_add(cnd,imm,ra); |
} else if (strcasecmp("OR",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_or(cnd,imm,rb,ra); |
else ins = op_or(cnd,imm,ra); |
} else if (strcasecmp("XOR",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_xor(cnd,imm,rb,ra); |
else ins = op_xor(cnd,imm,ra); |
} else if ((strcasecmp("LSL",opc)==0)||(strcasecmp("ASL",opc)==0)) { |
if (rb != ZIP_Rnone) |
ins = op_lsl(cnd,imm,rb,ra); |
else ins = op_lsl(cnd,imm,ra); |
} else if (strcasecmp("ASR",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_asr(cnd,imm,rb,ra); |
else ins = op_asr(cnd,imm,ra); |
} else if (strcasecmp("LSR",opc)==0) { |
if (rb != ZIP_Rnone) |
ins = op_lsr(cnd,imm,rb,ra); |
else ins = op_lsr(cnd,imm,ra); |
} else if (strcasecmp("BR",opc)==0) { |
if ((dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)) |
valid = false; |
else ins = op_bra(cnd, imm); |
} else if (strcasecmp("BRA",opc)==0) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_bra(imm); |
} else if (strcasecmp("BRZ",opc)==0) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_brz(imm); |
} else if ((strcasecmp("BRNZ",opc)==0)||(strcasecmp("BNZ",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_bnz(imm); |
} else if ((strcasecmp("BRGE",opc)==0)||(strcasecmp("BGE",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_bge(imm); |
} else if ((strcasecmp("BRGT",opc)==0)||(strcasecmp("BGT",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_bgt(imm); |
} else if (strcasecmp("BRZ",opc)==0) { |
} else if ((strcasecmp("BRLT",opc)==0)||(strcasecmp("BLT",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_blt(imm); |
} else if ((strcasecmp("BRC",opc)==0)||(strcasecmp("BC",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_brc(imm); |
} else if ((strcasecmp("BRV",opc)==0)||(strcasecmp("BV",opc)==0)) { |
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS)) |
valid = false; |
else ins = op_brv(imm); |
} else if (strcasecmp("CLRF",opc)==0) { |
if ((ra == ZIP_Rnone)&&(!dollar)&&(imm==0)) |
ins = op_clrf(cnd, rb); |
else valid = false; |
} else if((strcasecmp("HALT",opc)==0)||(strcasecmp("WAIT",opc)==0)) { |
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar)) |
ins = op_halt(cnd); |
else valid = false; |
} else if (strcasecmp("BUSY",opc)==0) { |
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar)) |
ins = op_busy(cnd); |
else valid = false; |
} else if (strcasecmp("RTU",opc)==0) { |
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(imm==0)&&(!opa)&&(!dollar)) |
ins = op_rtu(cnd); |
else { printf("ERRR,RTU, ra=%d,rb=%d,imm=%08x,comma=%s,dollar=%s\n", |
(int)ra, (int)rb, imm, (opa)?"true":"false", |
(dollar)?"true":"false"); |
valid = false; |
} |
} else if (strcasecmp("JMP",opc)==0) { |
if ((rb != ZIP_Rnone)&&(!opa)) |
ins = op_not(cnd, rb); |
else valid = false; |
} else if (strcasecmp("NOT",opc)==0) { |
if ((rb != ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar)) |
ins = op_not(cnd, rb); |
else valid = false; |
} else valid = false; |
|
return valid; |
} |
|
bool ZPARSER::parse(const char *line, ZPARSER::ZIPA &pc, ZPARSER::ZIPI &instruction, const unsigned int lineno) { |
bool v = parse_op(line, pc, instruction, lineno); |
pc = pc + 1; |
return v; |
} |
|
#define IMMOP(OP,CND,IMM,A) (((OP&0x0f)<<28)|((A&0x0f)<<24)|((CND&0x07)<<21) \ |
| (IMM & 0x0fffff)) |
|
93,12 → 439,8
|
ZIPI ZPARSER::op_trap(ZIPCOND cnd, ZIPIMM imm) const { |
ZIPI in; |
if (cnd != ZIPC_ALWAYS) |
return op_ldilo(cnd, imm, ZIP_CC); |
else |
return op_ldi(imm, ZIP_CC); |
// in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16); |
// in |= (imm & 0x0ffff); |
in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16); |
in |= (imm & 0x0ffff); |
return in; |
} |
|
/zipcpu/trunk/sw/zasm/zopcodes.cpp
4,10 → 4,7
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// |
// Purpose: A simple program to handle the disassembly and definition |
// of the various Zip Assembly opcodes. The primary function |
// of this file is the zipi_to_string, or Zip Instruction to |
// string (disassemble) conversion. |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
68,7 → 65,6
// Special case instructions. These are general instructions, but with |
// special opcodes |
// Conditional branches |
"BUSY", 0xffffffff, 0x2f0f7fff, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21), |
"BRA", 0xffff8000, 0x2f0f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED, |
"BRZ", 0xffff8000, 0x2f2f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED, |
"BNZ", 0xffff8000, 0x2f4f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED, |
/zipcpu/trunk/sw/zasm/zparser.h
4,14 → 4,7
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// |
// Purpose: This file is really mis-named. At one time it was going to |
// be header file for the parser for the Zip Assembler, zasm. |
// Since then, I discovered Flex and Bison and have written a |
// parser using those tools. The true parser may therefore be |
// found in zasm.y. This file, however, still declares some |
// very valuable tools. In particular, all of the routines used |
// to build instructions from the appropriate fields are declared |
// in this file. |
// Purpose: The beginnings of a parser for Zip CPU assembly. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
63,6 → 56,10
ZIPC_C, ZIPC_V |
} ZIPCOND; |
|
bool iscomment(const char *line) const; |
bool islabel(const char *line) const; |
bool parse_op(const char *line, ZIPA pc, ZIPI &instruction, const unsigned lineno) const; |
bool parse(const char *line, ZIPA &pc, ZIPI &instruction, const unsigned lineno); |
|
ZIPI op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const; |
ZIPI op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const; |
/zipcpu/trunk/sw/zasm/optest.cpp
4,10 → 4,7
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// |
// Purpose: A quick test of whether we can decode opcodes properly. This |
// test bypasses the assembler, and is useful when the assembler |
// isn't working. Now that we've got the assembler running, this |
// code isn't nearly as useful anymore. |
// Purpose: A quick test of whether we can decode opcodes properly. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
/zipcpu/trunk/sw/zasm/test.S
8,8 → 8,8
; the CPU. As a disorganized test, it doesn't prove anything |
; beyond the generic operation of the CPU. |
; |
; Status: As of August, 2015, this file assembles, builds, and passes |
; all of its tests in the Verilator simulator. |
; Status: As of July, 2015, the assembler isn't sophisticated enough |
; to handle the address resolution needed to assemble this file. |
; |
; Creator: Dan Gisselquist, Ph.D. |
; Gisselquist Tecnology, LLC |
34,135 → 34,9
; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; |
sys.bus equ 0xc0000000 |
sys.breaken equ 0x080 |
sys.step equ 0x040 |
sys.gie equ 0x020 |
sys.sleep equ 0x010 |
sys.ccv equ 0x008 |
sys.ccn equ 0x004 |
sys.ccc equ 0x002 |
sys.ccz equ 0x001 |
sys.bu.pic equ 0x000 |
sys.bus.wdt equ 0x001 |
sys.bus.cache equ 0x002 |
sys.bus.ctrpic equ 0x003 |
sys.bus.tma equ 0x004 |
sys.bus.tmb equ 0x005 |
sys.bus.tmc equ 0x006 |
sys.bus.jiffies equ 0x007 |
sys.bus.mtask equ 0x008 |
sys.bus.mpstl equ 0x009 |
sys.bus.mastl equ 0x00a |
sys.bus.mstl equ 0x00b |
sys.bus.utask equ 0x00c |
sys.bus.upstl equ 0x00d |
sys.bus.uastl equ 0x00e |
sys.bus.ustl equ 0x00f |
#define DO_TEST_ASSEMBLER |
test: |
#ifdef DO_TEST_ASSEMBLER |
; We start out by testing our assembler. We give it some instructions, which |
; are then manually checked by disassembling/dumping the result and making |
; certain they match. This is not an automated test, but it is an important |
; one. |
noop |
bra continue_test_with_testable_instructions |
break |
wait |
busy |
rtu |
continue_test_with_testable_instructions: |
; Now, let's place the assembler into a known state |
clr r0 |
clr r1 |
clr r2 |
clr r3 |
clr r4 |
clr r5 |
clr r6 |
clr r7 |
clr r9 |
clr r10 |
clr r11 |
clr r12 |
clr r13 |
; Don't clear the CC register |
; Don't clear the SP register |
; And repeat for the user registers |
mov R0,uR0 |
mov R0,uR1 |
mov R0,uR2 |
mov R0,uR3 |
mov R0,uR4 |
mov R0,uR5 |
mov R0,uR6 |
mov R0,uR7 |
mov R0,uR8 |
mov R0,uR9 |
mov R0,uR10 |
mov R0,uR11 |
mov R0,uR12 |
mov R0,uR13 |
mov R0,uCC |
; Don't clear the user PC register |
; Now, let's try loading some constants into registers |
dead_beef equ 0xdeadbeef |
ldi 0x0dead,r5 |
ldi 0x0beef,r6 |
ldi 0xdeadbeef,r7 |
ldihi 0xdead, r8 |
ldilo 0xbeef, r8 |
ldi dead_beef,r9 |
cmp r5,r6 |
bz test_failure |
cmp r7,r8 |
bnz test_failure |
ldi $deadbeefh,r7 ; Try loading with the $[HEX]h mneumonic |
cmp r7,r8 |
bnz test_failure |
cmp r7,r9 |
bnz test_failure |
bra skip_dead_beef |
dead_beef.base: |
word 0 |
fill 5,dead_beef |
word 0 |
dead_beef.zero equ 0 |
dead_beef.values equ 1 |
skip_dead_beef: |
lod dead_beef.base(pc),r10 ; Should load a zero here |
cmp r10,r11 ; r11 should still be zero from init abv |
bnz test_failure |
mov dead_beef.base(pc),r10 ; Now, let's get the address |
lod dead_beef.values(r10),r10 ; r10 now equals 0xdeadbeef |
cmp r10,r9 |
bnz test_failure |
|
; Test whether or not we can properly decode OCTAL values |
clr r0 ; Re-clear our register set first |
clr r1 |
clr r2 |
clr r3 |
clr r4 |
clr r5 |
clr r6 |
clr r7 |
clr r9 |
clr r10 |
clr r11 |
clr r12 |
clr r13 |
; |
ldi $024o,r0 |
ldi $20,r1 |
cmp r0,r1 |
bnz test_failure |
ldi $024,r0 |
cmp r0,r1 |
bnz test_failure |
clr r0 |
clr r1 |
mov r0,r1 |
mov $1+r0,r2 |
mov $2+r0,r3 |
mov $22h+r0,r4 |
172,76 → 46,30
add r2,r0 |
add $32,r0 |
add $-33,r0 |
bnz test_failure |
not.z r0 |
bge test_failure |
junk_address: |
clrf r0 |
bnz test_failure |
ldi $5,r1 |
cmp $0+r0,r1 |
not.lt r0 |
not.ge r1 |
mov junk_address(pc),r2 ; Test pc-relative addressing |
mov junk_address(pc),r3 |
cmp r2,r3 |
bnz test_failure |
lod junk_address(pc),r5 ; Test loads with pc-relative addressing |
lod junk_address(pc),r6 |
cmp r5,r6 |
bnz test_failure |
; Now, let's test whether or not our LSR and carry flags work |
ldi -1,r0 ; First test: shifting all the way should yield zero |
lsr 32,r0 |
cmp 0,r0 |
bnz test_failure |
ldi -1,r0 ; Second test: anything greater than zero should set |
lsr 0,r0 ; the carry flag |
bc test_failure |
lsr 1,r0 |
tst sys.ccc,cc |
bz test_failure |
lsr 31,r0 |
tst sys.ccc,cc |
bz test_failure |
lsr 1,r0 |
bc test_failure |
; Now repeat the above tests, looking to see whether or not ASR works |
ldi -1,r0 |
asr 32,r0 |
cmp -1,r0 |
bnz test_failure |
ldi -1,r0 |
asr 0,r0 |
bc test_failure |
cmp -1,r0 |
bnz test_failure |
asr 1,r0 |
tst sys.ccc,r14 |
bz test_failure |
asr 30,r0 |
tst sys.ccc,r14 |
bz test_failure |
#endif |
lod $-7+pc,r2 |
ldihi $deadh,r3 |
ldihi $beefh,r3 |
|
#ifdef NOONE // Testing comments after ifdef |
#else ; After else |
#endif /* and after endif */ |
testbench: |
// Let's build a software test bench. |
ldi $c0000000h,r12 ; Set R12 to point to our peripheral address |
clr r12 ; R12 will point to our peripherals |
ldihi $c000h,r12 |
mov r12,ur12 |
mov test_start(pc),upc |
ldi 0x8000ffff,r0 ; Clear interrupts, turn all vectors off |
sto r0,(r12) |
mov test_start,upc |
ldihi $8001,r0 |
ldilo $-1,r0 |
sto r0,$1+r12 |
rtu |
mov ucc,r0 |
tst -256,r0 |
bnz test_failure |
lod r12,r0 |
cmp $0,r0 |
bnz $1 |
halt |
// Go into an infinite loop if the trap fails |
// Permanent loop instruction -- a busy halt if you will |
test_failure: |
busy |
|
; Now for a series of tests. If the test fails, call the trap |
248,77 → 76,77
; interrupt with the test number that failed. Upon completion, |
; call the trap with #0. |
|
; Now for a series of tests. If the test fails, call the trap |
; interrupt with the test number that failed. Upon completion, |
; call the trap with #0. |
|
; Test LDI to PC |
; Some data registers |
test_data: |
.dat __here__+0x0100000+5 |
.dat __here__+5 |
test_start: |
ldi $0x0100,r11 |
lod test_data+pc,pc |
ldi $2,r11 |
lod $-3+pc,pc |
clr r11 |
noop |
cmp $0,r11 |
trap.z r11 |
sto.z r11,(r12) |
add $1,r0 |
add $1,r0 |
|
// Let's test whether overflow works |
ldi $0x0200,r11 |
ldi $3,r11 |
ldi $-1,r0 |
lsr $1,r0 |
add $1,r0 |
bv first_overflow_passes |
trap r11 |
first_overflow_passes: |
bv $1 |
sto r11,(r12) |
// Overflow set from subtraction |
ldi $0x0300,r11 |
ldi $4,r11 |
ldi $1,r0 |
rol $31,r0 ; rol $31,r0 |
.dat 0x5000001f ; rol $31,r0 |
sub $1,r0 |
bv subtraction_overflow_passes |
trap r11 |
subtraction_overflow_passes: |
bv $1 |
sto r11,(r12) |
// Overflow set from LSR |
ldi $0x0400,r11 |
ldi $5,r11 |
ldi $1,r0 |
rol $31,r0 ; rol $31,r0 |
.dat 0x5000001f ; rol $31,r0 |
lsr $1,r0 |
bv lsr_overflow_passes |
trap r11 |
lsr_overflow_passes: |
bv $1 |
sto r11,(r12) |
// Overflow set from LSL |
ldi $0x0500,r11 |
ldi $6,r11 |
ldi $1,r0 |
rol $30,r0 |
.dat 0x5000001e |
lsl $1,r0 |
bv lsl_overflow_passes |
trap r11 |
lsl_overflow_passes: |
bv $1 |
sto r11,(r12) |
|
// Overflow set from LSL, negative to positive |
ldi $0x0600,r11 |
ldi $7,r11 |
ldi $1,r0 |
rol $31,r0 |
.dat 0x5000001f; // E: ROL $30,R0 |
lsl $1,r0 |
bv second_lsl_overflow_passes |
trap r11 |
second_lsl_overflow_passes: |
bv $1 |
sto r11,(r12) |
|
// Test carry |
ldi $0x0700,r11 |
ldi $0x010,r11 |
ldi $-1,r0 |
add $1,r0 |
tst $2,cc |
trap.z r11 |
sto.z r11,(r12) |
// and carry from subtraction |
ldi $0x0800,r11 |
ldi $17,r11 |
sub $1,r0 |
tst $2,cc |
trap.z r11 |
sto.z r11,(r12) |
|
// Let's try a loop: for i=0; i<5; i++) |
// We'll use R0=i, Immediates for 5 |
ldi $0x0800,r11 |
for_loop: |
ldi $18,r11 |
clr r0 |
for_loop: |
noop |
add $1,r0 |
cmp $5,r0 |
330,8 → 158,8
// R0 = 5; (from before) |
// do { |
// } while (R0 > 0); |
ldi $0x0900,r11 |
bgt_loop: |
ldi $19,r11 |
noop |
sub $1,r0 |
bgt bgt_loop |
340,7 → 168,7
// R1 = 5; // Need to do this explicitly |
// do { |
// } while(R1 >= 0); |
ldi $20,r0 |
ldi $20,r00 |
ldi $5,r1 |
bge_loop: |
noop |
352,31 → 180,31
// R0 = 5; (from before) |
// do { |
// } while (R0 > 0); |
ldi $0x0a00,r11 |
bra mem_loop_test |
ldi $21,r11 |
bra $1 |
loop_var: |
.dat 0 |
mem_loop_test: |
mov loop_var(pc),r1 |
mem_loop: |
mov $-2+pc,r1 |
clr r2 |
ldi $5,r0 |
clr r2 |
sto r0,(r1) |
mem_loop: |
sto r1,(r0) |
add $1,r2 |
add $14,r0 |
lod (r1),r0 |
sub $1,r0 |
sto r0,(r1) |
bgt mem_loop |
bgt $-6 |
cmp $5,r2 |
trap.ne r11 |
sto.ne r11,(r12) |
|
// Return success / Test the trap interrupt |
clr r11 |
trap r11 |
sto r11,(r12) |
noop |
noop |
|
// Go into an infinite loop if the trap fails |
// Permanent loop instruction -- a busy halt if you will |
busy |
|
// And, in case we miss a halt ... |
/zipcpu/trunk/sw/zasm/obj-pc/depends.txt
1,4 → 1,3
obj-pc/asmdata.o: asmdata.cpp asmdata.h zopcodes.h zparser.h |
obj-pc/optest.o: optest.cpp zopcodes.h |
obj-pc/twoc.o: twoc.cpp twoc.h |
obj-pc/zasm.o: zasm.cpp zopcodes.h zparser.h |
/zipcpu/trunk/sw/zasm/zopcodes.h
48,7 → 48,7
#define IMMFIELD(LN,MN) (0x40000000 + (((LN&0x0ff)<<8)+(MN&0x0ff))) // Sgn extnd |
// #define REGVAL(V) ((V & 0x0f)+0x020) |
|
typedef unsigned int ZIPI; // A Zip CPU instruction |
typedef unsigned int ZIPI; |
|
typedef struct { |
char s_opstr[8]; |
/zipcpu/trunk/sw/zasm/Makefile
4,19 → 4,9
# |
# Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
# |
# Purpose: This makefile builds an assembler preprocessor (zpp), an |
# assembler (zasm) and a disassembler (zdump). Make with no |
# arguments will produce these files. Other targets include: |
# Purpose: This makefile builds an assembler and disassembler. |
# |
# make clean |
# make test |
# Assembles a test file and then produces a disassembly of it. |
# make depends |
# Doesn't work. Dependencies are currently all hand coded. |
# make optest |
# make tags |
# |
# |
# Creator: Dan Gisselquist, Ph.D. |
# Gisselquist Tecnology, LLC |
# |
40,16 → 30,16
# |
################################################################################ |
# |
.PHONY: all |
all: zasm optest zdump |
OBJDIR= obj-pc |
CXX= g++ |
CC= gcc |
YACC= bison |
LEX= flex |
YYMMDD=`date +%Y%m%d` |
DBGFLAGS= -g -O0 |
OPTFLAGS= -O3 |
CCFLAGS= $(DBGFLAGS) |
PROGRAMS= zasm optest zdump zpp |
PROGRAMS= zasm optest zdump |
|
.PHONY: programs |
all: $(OBJDIR)/ programs |
56,29 → 46,11
|
programs: $(PROGRAMS) |
|
$(OBJDIR)/zpp.cpp: zpp.l |
$(LEX) -o $@ $^ |
$(OBJDIR)/zpp.o: $(OBJDIR)/zpp.cpp |
$(CXX) -c $(CCFLAGS) $(OBJDIR)/zpp.cpp -o $@ |
zpp: $(OBJDIR)/zpp.o |
$(CXX) -o $@ $(CCFLAGS) $^ |
ZASMSRC= zasm.cpp zopcodes.cpp zparser.cpp twoc.cpp |
ZASMOBJ= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(ZASMSRC))) |
zasm: $(ZASMOBJ) |
$(CXX) $(CCFLAGS) $(ZASMOBJ) -o $@ |
|
$(OBJDIR)/zasm.tab.h: zasm.y asmdata.h zparser.h |
$(YACC) -b $(OBJDIR)/zasm -d zasm.y |
zasm.output: zasm.y asmdata.h |
$(YACC) -v -b $(OBJDIR)/zasm -d zasm.y |
$(OBJDIR)/zasm.lex.cpp: zasm.l $(OBJDIR)/zasm.tab.h |
$(LEX) -o $@ zasm.l |
$(OBJDIR)/zasm.lex.o: $(OBJDIR)/zasm.lex.cpp |
$(CXX) -c -I. -I$(OBJDIR)/ $(CCFLAGS) $(OBJDIR)/zasm.lex.cpp -o $@ |
$(OBJDIR)/zasm.tab.o: $(OBJDIR)/zasm.tab.c |
$(CXX) -c -I. -I$(OBJDIR)/ $(CCFLAGS) $(OBJDIR)/zasm.tab.c -o $@ |
$(OBJDIR)/asmdata.o: asmdata.cpp zopcodes.h zparser.h |
$(CXX) -c -I. $(CCFLAGS) asmdata.cpp -o $@ |
zasm: $(OBJDIR)/zasm.lex.o $(OBJDIR)/zasm.tab.o $(OBJDIR)/asmdata.o |
zasm: $(OBJDIR)/zparser.o $(OBJDIR)/zopcodes.o $(OBJDIR)/twoc.o |
$(CXX) -o $@ $(CCFLAGS) $^ |
|
optest: optest.cpp zopcodes.cpp twoc.cpp twoc.h zopcodes.h |
$(CXX) $(CCFLAGS) optest.cpp zopcodes.cpp twoc.cpp -o optest |
|
93,16 → 65,9
$(OBJDIR)/: |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
|
.PHONY: test |
test: dumpd.txt |
z.out: test.S zasm zdump |
./zasm test.S -o z.out |
dumpd.txt: z.out zdump |
./zdump z.out > dumpd.txt |
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CXX) -I $(OBJDIR)/ $(CCFLAGS) -MM *.cpp > xd.txt |
@$(CXX) $(CCFLAGS) -MM *.cpp > xd.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < xd.txt > $(OBJDIR)/depends.txt |
@rm xd.txt |
endef |
115,13 → 80,19
depends: tags |
$(build-depends) |
|
$(OBJDIR)/depends.txt: $(SOURCES) $(HEADERS) |
$(OBJDIR)/depends.txt: $(OBJDIR)/ $(SOURCES) $(HEADERS) |
$(build-depends) |
|
.PHONY: clean |
clean: |
rm -rf $(OBJDIR) $(PROGRAMS) z.out dumpd.txt |
rm -rf $(OBJDIR) $(PROGRAMS) |
|
-include $(OBJDIR)/depends.txt |
|
|
|
|
|
|
|
|