URL
https://opencores.org/ocsvn/plasma/plasma/trunk
Subversion Repositories plasma
Compare Revisions
- This comparison shows the changes necessary to convert path
/plasma/tags/V2_1
- from Rev 350 to Rev 352
- ↔ Reverse comparison
Rev 350 → Rev 352
/tools/makefile
0,0 → 1,66
# NOTE: CC is for the x86 compiler to compile the PC based tools. |
# Gcc is for the MIPS test code. |
# If you get an error using GNU make.exe try a different make utility. |
# The MIPS gcc compiler libraries cause problems with GNU make. |
|
CC = cl /O1 |
#CC = gcc_x86 -O |
|
all: convert.exe mlite.exe tracehex.exe bintohex.exe |
@echo make targets = count, opcodes, pi, test, run, tohex |
|
convert.exe: convert.c |
@$(CC) -o convert.exe convert.c |
|
mlite.exe: mlite.c |
@$(CC) -o mlite.exe mlite.c |
|
tracehex.exe: tracehex.c |
@$(CC) -o tracehex.exe tracehex.c |
|
bintohex.exe: bintohex.c |
@$(CC) -o bintohex.exe bintohex.c |
|
tohex: |
bintohex test2.exe |
copy code*.hex ..\vhdl |
|
opcodes: all |
as -o opcodes.o opcodes.asm |
ld -Ttext 0 -eentry -Map test.map -s -N -o test.exe opcodes.o |
-@objdump --disassemble test.exe > test.lst |
@convert |
-@mlite test2.exe BD > test.txt |
@copy code.txt ..\vhdl |
|
test: all |
as -o boot.o boot.asm |
gcc -O -DMLITE -Dmain=main2 -Wall -c -s test.c |
ld -Ttext 0 -eentry -Map test.map -s -N -o test.exe boot.o test.o |
-@objdump --disassemble test.exe > test.lst |
@convert |
-@mlite test2.exe BD > test.txt |
@copy code.txt ..\vhdl |
|
count: all |
as -o boot.o boot.asm |
gcc -O -DMLITE -Dmain=main2 -Wall -c -s count.c |
ld -Ttext 0 -eentry -Map test.map -s -N -o test.exe boot.o count.o |
-objdump --disassemble test.exe > test.lst |
convert |
-mlite test2.exe BD > test.txt |
copy code.txt ..\vhdl |
|
pi: all |
as -o boot.o boot.asm |
gcc -O -DMLITE -Dmain=main2 -Wall -c -s pi.c |
ld -Ttext 0 -eentry -Map test.map -s -N -o test.exe boot.o pi.o |
@objdump --disassemble test.exe > test.lst |
@convert |
-@mlite test2.exe BD > test.txt |
@copy code.txt ..\vhdl |
|
run: mlite.exe |
@mlite test2.exe B |
|
|
/tools/opcodes.asm
0,0 → 1,1039
################################################################## |
# TITLE: Opcode Tester |
# AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
# DATE CREATED: 1/10/02 |
# FILENAME: opcodes.asm |
# PROJECT: Plasma CPU core |
# COPYRIGHT: Software placed into the public domain by the author. |
# Software 'as is' without warranty. Author liable for nothing. |
# DESCRIPTION: |
# This assembly file tests all of the opcodes supported by the |
# Plasma core. |
# This test assumes that address 0xffff is the UART write register |
# Successful tests will print out "A" or "AB" or "ABC" or .... |
# Missing letters or letters out of order indicate a failure. |
################################################################## |
.text |
.align 2 |
.globl entry |
.ent entry |
entry: |
.set noreorder |
|
#These four instructions must be the first instructions |
#convert.exe will correctly initialize $gp |
lui $gp,0 |
ori $gp,$gp,0 |
#convert.exe will set $4=.sbss_start $5=.bss_end |
lui $4,0 |
ori $4,$4,0 |
lui $5,0 |
ori $5,$5,0 |
lui $sp,0 |
ori $sp,$sp,0xfff0 |
|
mtc0 $0,$12 #disable interrupts |
ori $20,$0,0xffff #serial port write address |
ori $21,$0,'\n' #<CR> letter |
ori $22,$0,'X' #'X' letter |
ori $23,$0,'\r' |
ori $24,$0,0x0f80 #temp memory |
|
###################################### |
#Arithmetic Instructions |
###################################### |
ori $2,$0,'A' |
sb $2,0($20) |
ori $2,$0,'r' |
sb $2,0($20) |
ori $2,$0,'i' |
sb $2,0($20) |
ori $2,$0,'t' |
sb $2,0($20) |
ori $2,$0,'h' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: ADD |
ori $2,$0,'a' |
sb $2,0($20) |
ori $3,$0,5 |
ori $4,$0,60 |
add $2,$3,$4 |
sb $2,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#b: ADDI |
ori $2,$0,'b' |
sb $2,0($20) |
ori $4,$0,60 |
addi $2,$4,5 |
sb $2,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#c: ADDIU |
ori $2,$0,'c' |
sb $2,0($20) |
ori $4,$0,50 |
addiu $5,$4,15 |
sb $5,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#d: ADDU |
ori $2,$0,'d' |
sb $2,0($20) |
ori $3,$0,5 |
ori $4,$0,60 |
add $2,$3,$4 |
sb $2,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#e: DIV |
ori $2,$0,'e' |
sb $2,0($20) |
ori $2,$0,65*117+41 |
ori $3,$0,117 |
div $2,$3 |
nop |
mflo $4 |
sb $4,0($20) #A |
mfhi $4 |
addi $4,$4,66-41 |
sb $4,0($20) #B |
li $2,-67*19 |
ori $3,$0,19 |
div $2,$3 |
nop |
mflo $4 |
sub $4,$0,$4 |
sb $4,0($20) #C |
ori $2,$0,68*23 |
li $3,-23 |
div $2,$3 |
nop |
mflo $4 |
sub $4,$0,$4 |
sb $4,0($20) #D |
li $2,-69*13 |
li $3,-13 |
div $2,$3 |
mflo $4 |
sb $4,0($20) #E |
sb $23,0($20) |
sb $21,0($20) |
|
#f: DIVU |
ori $2,$0,'f' |
sb $2,0($20) |
ori $2,$0,65*13 |
ori $3,$0,13 |
divu $2,$3 |
nop |
mflo $4 |
sb $4,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#g: MULT |
ori $2,$0,'g' |
sb $2,0($20) |
ori $2,$0,5 |
ori $3,$0,13 |
mult $2,$3 |
nop |
mflo $4 |
sb $4,0($20) #A |
li $2,-5 |
ori $3,$0,13 |
mult $2,$3 |
mfhi $5 |
mflo $4 |
sub $4,$0,$4 |
addu $4,$4,$5 |
addi $4,$4,2 |
sb $4,0($20) #B |
ori $2,$0,5 |
li $3,-13 |
mult $2,$3 |
mfhi $5 |
mflo $4 |
sub $4,$0,$4 |
addu $4,$4,$5 |
addi $4,$4,3 |
sb $4,0($20) #C |
li $2,-5 |
li $3,-13 |
mult $2,$3 |
mfhi $5 |
mflo $4 |
addu $4,$4,$5 |
addi $4,$4,3 |
sb $4,0($20) #D |
lui $4,0xfe98 |
ori $4,$4,0x62e5 |
lui $5,0x6 |
ori $5,0x8db8 |
mult $4,$5 |
mfhi $6 |
addiu $7,$6,2356+1+'E' #E |
sb $7,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#h: MULTU |
ori $2,$0,'h' |
sb $2,0($20) |
ori $2,$0,5 |
ori $3,$0,13 |
multu $2,$3 |
nop |
mflo $4 |
sb $4,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#i: SLT |
ori $2,$0,'i' |
sb $2,0($20) |
ori $2,$0,10 |
ori $3,$0,12 |
slt $4,$2,$3 |
addi $5,$4,64 |
sb $5,0($20) #A |
slt $4,$3,$2 |
addi $5,$4,66 |
sb $5,0($20) #B |
li $2,0xfffffff0 |
slt $4,$2,$3 |
addi $5,$4,66 |
sb $5,0($20) #C |
slt $4,$3,$2 |
addi $5,$4,68 |
sb $5,0($20) #D |
li $3,0xffffffff |
slt $4,$2,$3 |
addi $5,$4,68 |
sb $5,0($20) #E |
slt $4,$3,$2 |
addi $5,$4,70 |
sb $5,0($20) #F |
sb $23,0($20) |
sb $21,0($20) |
|
#j: SLTI |
ori $2,$0,'j' |
sb $2,0($20) |
ori $2,$0,10 |
slti $4,$2,12 |
addi $5,$4,64 |
sb $5,0($20) #A |
slti $4,$2,8 |
addi $5,$4,66 |
sb $5,0($20) #B |
sb $23,0($20) |
sb $21,0($20) |
|
#k: SLTIU |
ori $2,$0,'k' |
sb $2,0($20) |
ori $2,$0,10 |
sltiu $4,$2,12 |
addi $5,$4,64 |
sb $5,0($20) #A |
sltiu $4,$2,8 |
addi $5,$4,66 |
sb $5,0($20) #B |
sb $23,0($20) |
sb $21,0($20) |
|
#l: SLTU |
ori $2,$0,'l' |
sb $2,0($20) |
ori $2,$0,10 |
ori $3,$0,12 |
slt $4,$2,$3 |
addi $5,$4,64 |
sb $5,0($20) #A |
slt $4,$3,$2 |
addi $5,$4,66 |
sb $5,0($20) #B |
sb $23,0($20) |
sb $21,0($20) |
|
#m: SUB |
ori $2,$0,'m' |
sb $2,0($20) |
ori $3,$0,70 |
ori $4,$0,5 |
sub $2,$3,$4 |
sb $2,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
#n: SUBU |
ori $2,$0,'n' |
sb $2,0($20) |
ori $3,$0,70 |
ori $4,$0,5 |
sub $2,$3,$4 |
sb $2,0($20) #A |
sb $23,0($20) |
sb $21,0($20) |
|
###################################### |
#Branch and Jump Instructions |
###################################### |
ori $2,$0,'B' |
sb $2,0($20) |
ori $2,$0,'r' |
sb $2,0($20) |
ori $2,$0,'a' |
sb $2,0($20) |
ori $2,$0,'n' |
sb $2,0($20) |
ori $2,$0,'c' |
sb $2,0($20) |
ori $2,$0,'h' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: B |
ori $2,$0,'a' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
b $B1 |
sb $10,0($20) |
sb $22,0($20) |
$B1: |
sb $11,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#b: BAL |
ori $2,$0,'b' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $15,$0,'X' |
bal $BAL1 |
sb $10,0($20) |
sb $13,0($20) |
b $BAL2 |
sb $14,0($20) |
sb $15,0($20) |
$BAL1: |
sb $11,0($20) |
jr $31 |
sb $12,0($20) |
sb $22,0($20) |
$BAL2: |
sb $23,0($20) |
sb $21,0($20) |
|
#c: BEQ |
ori $2,$0,'c' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $2,$0,100 |
ori $3,$0,123 |
ori $4,$0,123 |
beq $2,$3,$BEQ1 |
sb $10,0($20) |
sb $11,0($20) |
beq $3,$4,$BEQ1 |
sb $12,0($20) |
sb $22,0($20) |
$BEQ1: |
sb $13,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#d: BGEZ |
ori $2,$0,'d' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
or $15,$0,'X' |
ori $2,$0,100 |
li $3,0xffff1234 |
ori $4,$0,123 |
bgez $3,$BGEZ1 |
sb $10,0($20) |
sb $11,0($20) |
bgez $2,$BGEZ1 |
sb $12,0($20) |
sb $22,0($20) |
$BGEZ1: |
bgez $0,$BGEZ2 |
nop |
sb $15,0($20) |
$BGEZ2: |
sb $13,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#e: BGEZAL |
ori $2,$0,'e' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $15,$0,'X' |
li $3,0xffff1234 |
bgezal $3,$BGEZAL1 |
nop |
sb $10,0($20) |
bgezal $0,$BGEZAL1 |
nop |
sb $13,0($20) |
b $BGEZAL2 |
sb $14,0($20) |
sb $15,0($20) |
$BGEZAL1: |
sb $11,0($20) |
jr $31 |
sb $12,0($20) |
sb $22,0($20) |
$BGEZAL2: |
sb $23,0($20) |
sb $21,0($20) |
|
#f: BGTZ |
ori $2,$0,'f' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $2,$0,100 |
li $3,0xffff1234 |
bgtz $3,$BGTZ1 |
sb $10,0($20) |
sb $11,0($20) |
bgtz $2,$BGTZ1 |
sb $12,0($20) |
sb $22,0($20) |
$BGTZ1: |
sb $13,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#g: BLEZ |
ori $2,$0,'g' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $2,$0,100 |
li $3,0xffff1234 |
blez $2,$BLEZ1 |
sb $10,0($20) |
sb $11,0($20) |
blez $3,$BLEZ1 |
sb $12,0($20) |
sb $22,0($20) |
$BLEZ1: |
blez $0,$BLEZ2 |
nop |
sb $22,0($20) |
$BLEZ2: |
sb $13,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#h: BLTZ |
ori $2,$0,'h' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $2,$0,100 |
li $3,0xffff1234 |
ori $4,$0,0 |
bltz $2,$BLTZ1 |
sb $10,0($20) |
sb $11,0($20) |
bltz $3,$BLTZ1 |
sb $12,0($20) |
sb $22,0($20) |
$BLTZ1: |
bltz $4,$BLTZ2 |
nop |
sb $13,0($20) |
$BLTZ2: |
sb $14,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#i: BLTZAL |
ori $2,$0,'i' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $15,$0,'X' |
li $3,0xffff1234 |
bltzal $0,$BLTZAL1 |
nop |
sb $10,0($20) |
bltzal $3,$BLTZAL1 |
nop |
sb $13,0($20) |
b $BLTZAL2 |
sb $14,0($20) |
sb $15,0($20) |
$BLTZAL1: |
sb $11,0($20) |
jr $31 |
sb $12,0($20) |
sb $22,0($20) |
$BLTZAL2: |
sb $23,0($20) |
sb $21,0($20) |
|
#j: BNE |
ori $2,$0,'j' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $2,$0,100 |
ori $3,$0,123 |
ori $4,$0,123 |
bne $3,$4,$BNE1 |
sb $10,0($20) |
sb $11,0($20) |
bne $2,$3,$BNE1 |
sb $12,0($20) |
sb $22,0($20) |
$BNE1: |
sb $13,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#k: J |
ori $2,$0,'k' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $15,$0,'X' |
j $J1 |
sb $10,0($20) |
sb $15,0($20) |
$J1: |
sb $11,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#l: JAL |
ori $2,$0,'l' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $15,$0,'X' |
jal $JAL1 |
sb $10,0($20) |
sb $13,0($20) |
b $JAL2 |
sb $14,0($20) |
sb $15,0($20) |
$JAL1: |
sb $11,0($20) |
jr $31 |
sb $12,0($20) |
sb $22,0($20) |
$JAL2: |
sb $23,0($20) |
sb $21,0($20) |
|
#m: JALR |
ori $2,$0,'m' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $12,$0,'C' |
ori $13,$0,'D' |
ori $14,$0,'E' |
ori $15,$0,'X' |
la $3,$JALR1 |
jalr $3 |
sb $10,0($20) |
sb $13,0($20) |
b $JALR2 |
sb $14,0($20) |
sb $15,0($20) |
$JALR1: |
sb $11,0($20) |
jr $31 |
sb $12,0($20) |
sb $22,0($20) |
$JALR2: |
sb $23,0($20) |
sb $21,0($20) |
|
#n: JR |
ori $2,$0,'n' |
sb $2,0($20) |
ori $10,$0,'A' |
ori $11,$0,'B' |
ori $15,$0,'X' |
la $3,$JR1 |
jr $3 |
sb $10,0($20) |
sb $15,0($20) |
$JR1: |
sb $11,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#o: NOP |
ori $2,$0,'o' |
sb $2,0($20) |
ori $2,$0,65 |
nop |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
###################################### |
#Load, Store, and Memory Control Instructions |
###################################### |
ori $2,$0,'L' |
sb $2,0($20) |
ori $2,$0,'o' |
sb $2,0($20) |
ori $2,$0,'a' |
sb $2,0($20) |
ori $2,$0,'d' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: LB |
ori $2,$0,'a' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x41424344 |
sw $3,16($2) |
lb $4,16($2) |
sb $4,0($20) |
lb $4,17($2) |
sb $4,0($20) |
lb $4,18($2) |
sb $4,0($20) |
lb $2,19($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#b: LBU |
ori $2,$0,'b' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x41424344 |
sw $3,16($2) |
lb $4,16($2) |
sb $4,0($20) |
lb $4,17($2) |
sb $4,0($20) |
lb $4,18($2) |
sb $4,0($20) |
lb $2,19($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#c: LH |
ori $2,$0,'c' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x00410042 |
sw $3,16($2) |
lh $4,16($2) |
sb $4,0($20) |
lh $2,18($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#d: LHU |
ori $2,$0,'d' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x00410042 |
sw $3,16($2) |
lh $4,16($2) |
sb $4,0($20) |
lh $2,18($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#e: LW |
ori $2,$0,'e' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,'A' |
sw $3,16($2) |
ori $3,$0,0 |
lw $2,16($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#f: LWL & LWR |
ori $2,$0,'f' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,'A' |
sw $3,16($2) |
ori $3,$0,0 |
lwl $2,16($2) |
lwr $2,16($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#g: SB |
ori $2,$0,'g' |
sb $2,0($20) |
ori $2,$0,'A' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#h: SH |
ori $2,$0,'h' |
sb $2,0($20) |
or $4,$0,$24 |
ori $2,$0,0x4142 |
sh $2,16($4) |
lb $3,16($4) |
sb $3,0($20) |
lb $2,17($4) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#i: SW |
ori $2,$0,'i' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x41424344 |
sw $3,16($2) |
lb $4,16($2) |
sb $4,0($20) |
lb $4,17($2) |
sb $4,0($20) |
lb $4,18($2) |
sb $4,0($20) |
lb $2,19($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#j: SWL & SWR |
ori $2,$0,'j' |
sb $2,0($20) |
or $2,$0,$24 |
li $3,0x41424344 |
swl $3,16($2) |
swr $3,16($2) |
lb $4,16($2) |
sb $4,0($20) |
lb $4,17($2) |
sb $4,0($20) |
lb $4,18($2) |
sb $4,0($20) |
lb $2,19($2) |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
###################################### |
#Logical Instructions |
###################################### |
ori $2,$0,'L' |
sb $2,0($20) |
ori $2,$0,'o' |
sb $2,0($20) |
ori $2,$0,'g' |
sb $2,0($20) |
ori $2,$0,'i' |
sb $2,0($20) |
ori $2,$0,'c' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: AND |
ori $2,$0,'a' |
sb $2,0($20) |
ori $2,$0,0x0741 |
ori $3,$0,0x60f3 |
and $4,$2,$3 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#b: ANDI |
ori $2,$0,'b' |
sb $2,0($20) |
ori $2,$0,0x0741 |
andi $4,$2,0x60f3 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#c: LUI |
ori $2,$0,'c' |
sb $2,0($20) |
lui $2,0x41 |
srl $3,$2,16 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#d: NOR |
ori $2,$0,'d' |
sb $2,0($20) |
li $2,0xf0fff08e |
li $3,0x0f0f0f30 |
nor $4,$2,$3 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#e: OR |
ori $2,$0,'e' |
sb $2,0($20) |
ori $2,$0,0x40 |
ori $3,$0,0x01 |
or $4,$2,$3 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#f: ORI |
ori $2,$0,'f' |
sb $2,0($20) |
ori $2,$0,0x40 |
ori $4,$2,0x01 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#g: XOR |
ori $2,$0,'g' |
sb $2,0($20) |
ori $2,$0,0xf043 |
ori $3,$0,0xf002 |
xor $4,$2,$3 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#h: XORI |
ori $2,$0,'h' |
sb $2,0($20) |
ori $2,$0,0xf043 |
xor $4,$2,0xf002 |
sb $4,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
###################################### |
#Move Instructions |
###################################### |
ori $2,$0,'M' |
sb $2,0($20) |
ori $2,$0,'o' |
sb $2,0($20) |
ori $2,$0,'v' |
sb $2,0($20) |
ori $2,$0,'e' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: MFHI |
ori $2,$0,'a' |
sb $2,0($20) |
ori $2,$0,65 |
mthi $2 |
mfhi $3 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#b: MFLO |
ori $2,$0,'b' |
sb $2,0($20) |
ori $2,$0,65 |
mtlo $2 |
mflo $3 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#c: MTHI |
ori $2,$0,'c' |
sb $2,0($20) |
ori $2,$0,65 |
mthi $2 |
mfhi $3 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#d: MTLO |
ori $2,$0,'d' |
sb $2,0($20) |
ori $2,$0,65 |
mtlo $2 |
mflo $3 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
###################################### |
#Shift Instructions |
###################################### |
ori $2,$0,'S' |
sb $2,0($20) |
ori $2,$0,'h' |
sb $2,0($20) |
ori $2,$0,'i' |
sb $2,0($20) |
ori $2,$0,'f' |
sb $2,0($20) |
ori $2,$0,'t' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#a: SLL |
ori $2,$0,'a' |
sb $2,0($20) |
li $2,0x40414243 |
sll $3,$2,8 |
srl $3,$3,24 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#b: SLLV |
ori $2,$0,'b' |
sb $2,0($20) |
li $2,0x40414243 |
ori $3,$0,8 |
sllv $3,$2,$3 |
srl $3,$3,24 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#c: SRA |
ori $2,$0,'c' |
sb $2,0($20) |
li $2,0x40414243 |
sra $3,$2,16 |
sb $3,0($20) |
li $2,0x84000000 |
sra $3,$2,25 |
sub $3,$3,0x80 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#d: SRAV |
ori $2,$0,'d' |
sb $2,0($20) |
li $2,0x40414243 |
ori $3,$0,16 |
srav $3,$2,$3 |
sb $3,0($20) |
ori $3,$0,25 |
li $2,0x84000000 |
srav $3,$2,$3 |
sub $3,$3,0x80 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#e: SRL |
ori $2,$0,'e' |
sb $2,0($20) |
li $2,0x40414243 |
srl $3,$2,16 |
sb $3,0($20) |
li $2,0x84000000 |
srl $3,$2,25 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
#f: SRLV |
ori $2,$0,'f' |
sb $2,0($20) |
li $2,0x40414243 |
ori $3,$0,16 |
srlv $4,$2,$3 |
sb $4,0($20) |
ori $3,$0,25 |
li $2,0x84000000 |
srlv $3,$2,$3 |
sb $3,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
ori $2,$0,'D' |
sb $2,0($20) |
ori $2,$0,'o' |
sb $2,0($20) |
ori $2,$0,'n' |
sb $2,0($20) |
ori $2,$0,'e' |
sb $2,0($20) |
sb $23,0($20) |
sb $21,0($20) |
|
|
$DONE: |
j $DONE |
nop |
|
.set reorder |
.end entry |
|
/tools/boot.asm
0,0 → 1,106
################################################################## |
# TITLE: Boot Up Code |
# AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
# DATE CREATED: 1/12/02 |
# FILENAME: boot.asm |
# PROJECT: Plasma CPU core |
# COPYRIGHT: Software placed into the public domain by the author. |
# Software 'as is' without warranty. Author liable for nothing. |
# DESCRIPTION: |
# Initializes the stack pointer and jumps to main2(). |
################################################################## |
.text |
.align 2 |
.globl entry |
.ent entry |
entry: |
.set noreorder |
|
#These eight instructions must be the first instructions. |
#convert.exe will correctly initialize $gp |
lui $gp,0 |
ori $gp,$gp,0 |
#convert.exe will set $4=.sbss_start $5=.bss_end |
lui $4,0 |
ori $4,$4,0 |
lui $5,0 |
ori $5,$5,0 |
lui $sp,0 |
ori $sp,$sp,0xfff0 #initialize stack pointer |
$BSS_CLEAR: |
sw $0,0($4) |
slt $3,$4,$5 |
bnez $3,$BSS_CLEAR |
addiu $4,$4,4 |
|
jal main2 |
nop |
$L1: |
j $L1 |
|
#address 0x3c |
interrupt_service_routine: |
#registers $26 and $27 are reserved for the OS |
ori $26,$0,0xffff |
ori $27,$0,46 |
sb $27,0($26) #echo out '.' |
|
#normally clear the interrupt source here |
|
#return and re-enable interrupts |
ori $26,$0,0x1 |
mfc0 $27,$14 #C0_EPC=14 |
jr $27 |
mtc0 $26,$12 #STATUS=1; enable interrupts |
.set reorder |
.end entry |
|
|
################################################### |
.globl isr_enable |
.ent isr_enable |
isr_enable: |
.set noreorder |
jr $31 |
mtc0 $4,$12 #STATUS=1; enable interrupts |
.set reorder |
.end isr_enable |
|
|
################################################### |
.globl putchar |
.ent putchar |
putchar: |
.set noreorder |
li $5,0xffff |
|
#Uncomment to make each character on a seperate line |
#The VHDL simulator buffers the lines |
# sb $4,0($5) |
# ori $4,$0,'\n' |
|
jr $31 |
sb $4,0($5) |
.set reorder |
.end putchar |
|
|
################################################### |
.globl puts |
.ent puts |
puts: |
.set noreorder |
ori $5,$0,0xffff |
PUTS1: |
lb $6,0($4) |
beqz $6,PUTS2 |
addiu $4,$4,1 |
b PUTS1 |
sb $6,0($5) |
PUTS2: |
jr $31 |
ori $2,$0,0 |
.set reorder |
.end puts |
|
|
/tools/convert.c
0,0 → 1,207
//convert.c by Steve Rhoads 4/26/01 |
//Now uses the ELF format (get gccmips_elf.zip) |
//set $gp and zero .sbss and .bss |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
#define BUF_SIZE (1024*1024) |
/*Assumes running on PC little endian*/ |
#define ntohl(A) (((A)>>24)|(((A)&0x00ff0000)>>8)|(((A)&0xff00)<<8)|((A)<<24)) |
#define ntohs(A) ((((A)&0xff00)>>8)|((A)<<8)) |
|
#define EI_NIDENT 16 |
#define SHT_PROGBITS 1 |
#define SHT_STRTAB 3 |
#define SHT_NOBITS 8 |
|
typedef struct { |
unsigned char e_ident[EI_NIDENT]; |
unsigned short e_e_type; |
unsigned short e_machine; |
unsigned long e_version; |
unsigned long e_entry; |
unsigned long e_phoff; |
unsigned long e_shoff; |
unsigned long e_flags; |
unsigned short e_ehsize; |
unsigned short e_phentsize; |
unsigned short e_phnum; |
unsigned short e_shentsize; |
unsigned short e_shnum; |
unsigned short e_shstrndx; |
} ElfHeader; |
|
typedef struct { |
unsigned long p_type; |
unsigned long p_offset; |
unsigned long p_vaddr; |
unsigned long p_paddr; |
unsigned long p_filesz; |
unsigned long p_memsz; |
unsigned long p_flags; |
unsigned long p_align; |
} Elf32_Phdr; |
|
typedef struct { |
unsigned long sh_name; |
unsigned long sh_type; |
unsigned long sh_flags; |
unsigned long sh_addr; |
unsigned long sh_offset; |
unsigned long sh_size; |
unsigned long sh_link; |
unsigned long sh_info; |
unsigned long sh_addralign; |
unsigned long sh_entsize; |
} Elf32_Shdr; |
|
#if 0 |
unsigned long load(unsigned char *ptr,unsigned long address) |
{ |
unsigned long value; |
value=*(unsigned long*)(ptr+address); |
value=ntohl(value); |
return value; |
} |
|
unsigned short load_short(unsigned char *ptr,unsigned long address) |
{ |
return (ptr[address]<<8)+ptr[address+1]; |
} |
#endif |
|
void set_low(char *ptr,unsigned long address,unsigned long value) |
{ |
unsigned long opcode; |
opcode=*(unsigned long*)(ptr+address); |
opcode=ntohl(opcode); |
opcode=(opcode&0xffff0000)|(value&0xffff); |
opcode=ntohl(opcode); |
*(unsigned long*)(ptr+address)=opcode; |
} |
|
int main(int argc,char *argv[]) |
{ |
FILE *infile,*outfile,*txtfile; |
unsigned char *buf,*code; |
long size,stack_pointer; |
unsigned long length,d,i,gp_ptr=0; |
unsigned long bss_start=0,bss_end=0; |
|
ElfHeader *elfHeader; |
Elf32_Phdr *elfProgram; |
Elf32_Shdr *elfSection; |
|
printf("test.exe -> code.txt & test2.exe\n"); |
infile=fopen("test.exe","rb"); |
if(infile==NULL) { |
printf("Can't open test.exe"); |
return 0; |
} |
buf=(unsigned char*)malloc(BUF_SIZE); |
size=fread(buf,1,BUF_SIZE,infile); |
fclose(infile); |
code=(unsigned char*)malloc(BUF_SIZE); |
memset(code,0,BUF_SIZE); |
|
elfHeader=(ElfHeader*)buf; |
if(strncmp(elfHeader->e_ident+1,"ELF",3)) { |
printf("Error: Not an ELF file!\n"); |
printf("Use the gccmips_elf.zip from opencores/projects/plasma!\n"); |
return -1; |
} |
|
elfHeader->e_entry=ntohl(elfHeader->e_entry); |
elfHeader->e_phoff=ntohl(elfHeader->e_phoff); |
elfHeader->e_shoff=ntohl(elfHeader->e_shoff); |
elfHeader->e_phentsize=ntohs(elfHeader->e_phentsize); |
elfHeader->e_phnum=ntohs(elfHeader->e_phnum); |
elfHeader->e_shentsize=ntohs(elfHeader->e_shentsize); |
elfHeader->e_shnum=ntohs(elfHeader->e_shnum); |
length=0; |
|
for(i=0;i<elfHeader->e_phnum;++i) { |
elfProgram=(Elf32_Phdr*)(buf+elfHeader->e_phoff+elfHeader->e_phentsize*i); |
elfProgram->p_offset=ntohl(elfProgram->p_offset); |
elfProgram->p_vaddr=ntohl(elfProgram->p_vaddr); |
elfProgram->p_filesz=ntohl(elfProgram->p_filesz); |
elfProgram->p_memsz=ntohl(elfProgram->p_memsz); |
// printf("[0x%x,0x%x,0x%x]\n",elfProgram->p_vaddr,elfProgram->p_offset,elfProgram->p_filesz); |
memcpy(code+elfProgram->p_vaddr,buf+elfProgram->p_offset,elfProgram->p_filesz); |
length=elfProgram->p_vaddr+elfProgram->p_memsz; |
} |
|
for(i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(buf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
elfSection->sh_name=ntohl(elfSection->sh_name); |
elfSection->sh_type=ntohl(elfSection->sh_type); |
elfSection->sh_addr=ntohl(elfSection->sh_addr); |
elfSection->sh_offset=ntohl(elfSection->sh_offset); |
elfSection->sh_size=ntohl(elfSection->sh_size); |
#if 0 |
printf("{0x%x,0x%x:0x%x,0x%x,0x%x}\n", |
elfSection->sh_name,elfSection->sh_type,elfSection->sh_addr, |
elfSection->sh_offset,elfSection->sh_size); |
#endif |
#if 0 |
if(elfSection->sh_type==SHT_PROGBITS||elfSection->sh_type==SHT_STRTAB) { |
// memcpy(code+elfSection->sh_addr,buf+elfSection->sh_offset,elfSection->sh_size); |
length=elfSection->sh_addr+elfSection->sh_size; |
bss_start=length; |
} |
#endif |
if(elfSection->sh_type==SHT_PROGBITS) { |
gp_ptr=elfSection->sh_addr; |
} |
if(elfSection->sh_type==SHT_NOBITS) { |
if(bss_start==0) { |
bss_start=elfSection->sh_addr; |
} |
bss_end=elfSection->sh_addr+elfSection->sh_size; |
} |
} |
|
if(bss_start==length) { |
bss_start=length; |
bss_end=length+4; |
} |
|
/*Initialize the $gp register for sdata and sbss*/ |
gp_ptr+=0x7ff0; |
printf("gp_ptr=0x%x ",gp_ptr); |
/*modify the first opcodes in boot.asm*/ |
/*modify the lui opcode*/ |
set_low(code,0,gp_ptr>>16); |
/*modify the ori opcode*/ |
set_low(code,4,gp_ptr&0xffff); |
|
/*Clear .sbss and .bss*/ |
printf(".sbss=0x%x .bss_end=0x%x\n",bss_start,bss_end); |
set_low(code,8,bss_start>>16); |
set_low(code,12,bss_start&0xffff); |
set_low(code,16,bss_end>>16); |
set_low(code,20,bss_end&0xffff); |
|
/*Set stack pointer*/ |
stack_pointer=bss_end+512; |
printf("Stack pointer=0x%x\n",stack_pointer); |
set_low(code,24,stack_pointer>>16); |
set_low(code,28,stack_pointer&0xffff); |
|
/*write out code.txt*/ |
outfile=fopen("test2.exe","wb"); |
fwrite(code,length,1,outfile); |
fclose(outfile); |
|
txtfile=fopen("code.txt","w"); |
for(i=0;i<=length;i+=4) { |
d=ntohl(*(unsigned long*)(code+i)); |
fprintf(txtfile,"%8.8x\n",d); |
} |
fclose(txtfile); |
free(buf); |
|
return 0; |
} |
|
/tools/mlite.c
0,0 → 1,436
/*------------------------------------------------------------------- |
-- TITLE: Plasma CPU in software. Executes MIPS(tm) opcodes. |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 1/31/01 |
-- FILENAME: mlite.c |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Plasma CPU simulator in C code. |
-- This file served as the starting point for the VHDL code. |
--------------------------------------------------------------------*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <ctype.h> |
|
#define MEM_SIZE (1024*1024*2) |
#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) ) |
#define htons(A) ntohs(A) |
#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) ) |
#define htonl(A) ntohl(A) |
|
// int getch(void); |
#define getch getchar |
|
typedef struct { |
long r[32]; |
long pc,pc_next; |
long hi; |
long lo; |
long skip; |
char *mem; |
long wakeup; |
long big_endian; |
} State; |
|
static char *opcode_string[]={ |
"SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ", |
"ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI", |
"COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL", |
"?","?","?","?","?","?","?","?", |
"LB","LH","LWL","LW","LBU","LHU","LWR","?", |
"SB","SH","SWL","SW","?","?","SWR","CACHE", |
"LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3" |
"SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3" |
}; |
|
static char *special_string[]={ |
"SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV", |
"JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC", |
"MFHI","MTHI","MFLO","MTLO","?","?","?","?", |
"MULT","MULTU","DIV","DIVU","?","?","?","?", |
"ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR", |
"?","?","SLT","SLTU","?","DADDU","?","?", |
"TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?", |
"?","?","?","?","?","?","?","?" |
}; |
|
static char *regimm_string[]={ |
"BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?", |
"TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?", |
"BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?", |
"?","?","?","?","?","?","?","?" |
}; |
|
static long big_endian=0; |
|
static long mem_read(State *s,long size,unsigned long address) |
{ |
unsigned long value=0,ptr; |
address%=MEM_SIZE; |
ptr=(long)s->mem+address; |
switch(size) { |
case 4: value=*(long*)ptr; |
if(big_endian) value=ntohl(value); |
break; |
case 2: |
value=*(unsigned short*)ptr; |
if(big_endian) value=ntohs((unsigned short)value); |
break; |
case 1: |
value=*(unsigned char*)ptr; |
break; |
default: printf("ERROR"); |
} |
return(value); |
} |
|
static void mem_write(State *s,long size,long unsigned address,unsigned long value) |
{ |
static char_count=0; |
unsigned long ptr; |
if(address==0xffff) { //UART write register at 0xffff |
value&=0xff; |
if(isprint(value)) { |
printf("%c",value); |
if(++char_count>=72) { |
printf("\n"); |
char_count=0; |
} |
} else if(value=='\n') { |
printf("\n"); |
char_count=0; |
} else { |
printf("."); |
} |
} |
address%=MEM_SIZE; |
ptr=(long)s->mem+address; |
switch(size) { |
case 4: if(big_endian) value=htonl(value); |
*(long*)ptr=value; |
break; |
case 2: |
if(big_endian) { |
value=htons((unsigned short)value); |
} |
*(short*)ptr=(unsigned short)value; |
break; |
case 1: |
*(char*)ptr=(unsigned char)value; |
break; |
default: printf("ERROR"); |
} |
} |
|
void mult_big(unsigned long a,unsigned long b, |
unsigned long *hi,unsigned long *lo) |
{ |
unsigned long ahi,alo,bhi,blo; |
unsigned long c0,c1,c2,c3; |
unsigned long c1_a,c1_b,c2_a,c2_b; |
ahi=a>>16; |
alo=a&0xffff; |
bhi=b>>16; |
blo=b&0xffff; |
|
c0=alo*blo; |
c1_a=ahi*blo; |
c1_b=alo*bhi; |
c2=ahi*bhi; |
|
|
c2+=(c1_a>>16)+(c1_b>>16); |
c1=(c1_a&0xffff)+(c1_b&0xffff)+(c0>>16); |
c0&=0xffff; |
c2+=(c1>>16); |
c1&=0xffff; |
*hi=c2; |
*lo=(c1<<16)+c0; |
} |
|
//execute one cycle of a Plasma CPU |
void cycle(State *s,int show_mode) |
{ |
unsigned long opcode; |
unsigned long op,rs,rt,rd,re,func,imm,target; |
long imm_shift,branch=0,lbranch=2; |
long *r=s->r; |
unsigned long *u=(unsigned long*)s->r; |
unsigned long ptr; |
opcode=mem_read(s,4,s->pc); |
op=(opcode>>26)&0x3f; |
rs=(opcode>>21)&0x1f; |
rt=(opcode>>16)&0x1f; |
rd=(opcode>>11)&0x1f; |
re=(opcode>>6)&0x1f; |
func=opcode&0x3f; |
imm=opcode&0xffff; |
imm_shift=(((long)(short)imm)<<2)-4; |
target=(opcode<<6)>>4; |
ptr=(short)imm+r[rs]; |
r[0]=0; |
if(show_mode) { |
printf("%8.8lx %8.8lx ",s->pc,opcode); |
if(op==0) printf("%8s ",special_string[func]); |
else if(op==1) printf("%8s ",regimm_string[rt]); |
else printf("%8s ",opcode_string[op]); |
printf("$%2.2ld $%2.2ld $%2.2ld $%2.2ld ",rs,rt,rd,re); |
printf("%4.4lx\n",imm); |
} |
if(show_mode>5) return; |
s->pc=s->pc_next; |
s->pc_next=s->pc_next+4; |
if(s->skip) { |
s->skip=0; |
return; |
} |
switch(op) { |
case 0x00:/*SPECIAL*/ |
switch(func) { |
case 0x00:/*SLL*/ r[rd]=r[rt]<<re; break; |
case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break; |
case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break; |
case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break; |
case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break; |
case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break; |
case 0x08:/*JR*/ s->pc_next=r[rs]; break; |
case 0x09:/*JALR*/ r[rd]=s->pc_next; s->pc_next=r[rs]; break; |
case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/ |
case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/ |
case 0x0c:/*SYSCALL*/ break; |
case 0x0d:/*BREAK*/ s->wakeup=1; break; |
case 0x0f:/*SYNC*/ s->wakeup=1; break; |
case 0x10:/*MFHI*/ r[rd]=s->hi; break; |
case 0x11:/*FTHI*/ s->hi=r[rs]; break; |
case 0x12:/*MFLO*/ r[rd]=s->lo; break; |
case 0x13:/*MTLO*/ s->lo=r[rs]; break; |
case 0x18:/*MULT*/ |
case 0x19:/*MULTU*/ //s->lo=r[rs]*r[rt]; s->hi=0; break; |
mult_big(r[rs],r[rt],&s->hi,&s->lo); break; |
case 0x1a:/*DIV*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break; |
case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break; |
case 0x20:/*ADD*/ r[rd]=r[rs]+r[rt]; break; |
case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt]; break; |
case 0x22:/*SUB*/ r[rd]=r[rs]-r[rt]; break; |
case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt]; break; |
case 0x24:/*AND*/ r[rd]=r[rs]&r[rt]; break; |
case 0x25:/*OR*/ r[rd]=r[rs]|r[rt]; break; |
case 0x26:/*XOR*/ r[rd]=r[rs]^r[rt]; break; |
case 0x27:/*NOR*/ r[rd]=~(r[rs]|r[rt]); break; |
case 0x2a:/*SLT*/ r[rd]=r[rs]<r[rt]; break; |
case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt]; break; |
case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt]; break; |
case 0x31:/*TGEU*/ break; |
case 0x32:/*TLT*/ break; |
case 0x33:/*TLTU*/ break; |
case 0x34:/*TEQ*/ break; |
case 0x36:/*TNE*/ break; |
default: printf("ERROR0(*0x%x~0x%x)\n",s->pc,opcode); |
s->wakeup=1; |
} |
break; |
case 0x01:/*REGIMM*/ |
switch(rt) { |
case 0x10:/*BLTZAL*/ r[31]=s->pc_next; |
case 0x00:/*BLTZ*/ branch=r[rs]<0; break; |
case 0x11:/*BGEZAL*/ r[31]=s->pc_next; |
case 0x01:/*BGEZ*/ branch=r[rs]>=0; break; |
case 0x12:/*BLTZALL*/r[31]=s->pc_next; |
case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break; |
case 0x13:/*BGEZALL*/r[31]=s->pc_next; |
case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break; |
default: printf("ERROR1\n"); s->wakeup=1; |
} |
break; |
case 0x03:/*JAL*/ r[31]=s->pc_next; |
case 0x02:/*J*/ s->pc_next=(s->pc&0xf0000000)|target; break; |
case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break; |
case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break; |
case 0x06:/*BLEZ*/ branch=r[rs]<=0; break; |
case 0x07:/*BGTZ*/ branch=r[rs]>0; break; |
case 0x08:/*ADDI*/ r[rt]=r[rs]+(short)imm; break; |
case 0x09:/*ADDIU*/ u[rt]=u[rs]+(short)imm; break; |
case 0x0a:/*SLTI*/ r[rt]=r[rs]<(short)imm; break; |
case 0x0b:/*SLTIU*/ u[rt]=u[rs]<(unsigned long)(short)imm; break; |
case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break; |
case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break; |
case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break; |
case 0x0f:/*LUI*/ r[rt]=(imm<<16); break; |
case 0x10:/*COP0*/ break; |
// case 0x11:/*COP1*/ break; |
// case 0x12:/*COP2*/ break; |
// case 0x13:/*COP3*/ break; |
case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break; |
case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break; |
case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break; |
case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break; |
// case 0x1c:/*MAD*/ break; /*IV*/ |
case 0x20:/*LB*/ r[rt]=(signed char)mem_read(s,1,ptr); break; |
case 0x21:/*LH*/ r[rt]=(signed short)mem_read(s,2,ptr); break; |
case 0x22:/*LWL*/ rt=rt; //fixme fall through |
case 0x23:/*LW*/ r[rt]=mem_read(s,4,ptr); break; |
case 0x24:/*LBU*/ r[rt]=(unsigned char)mem_read(s,1,ptr); break; |
case 0x25:/*LHU*/ r[rt]=(unsigned short)mem_read(s,2,ptr); break; |
case 0x26:/*LWR*/ break; //fixme |
case 0x28:/*SB*/ mem_write(s,1,ptr,r[rt]); break; |
case 0x29:/*SH*/ mem_write(s,2,ptr,r[rt]); break; |
case 0x2a:/*SWL*/ rt=rt; //fixme fall through |
case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt]); break; |
case 0x2e:/*SWR*/ break; //fixme |
case 0x2f:/*CACHE*/break; |
case 0x30:/*LL*/ r[rt]=mem_read(s,4,ptr); break; |
// case 0x31:/*LWC1*/ break; |
// case 0x32:/*LWC2*/ break; |
// case 0x33:/*LWC3*/ break; |
// case 0x35:/*LDC1*/ break; |
// case 0x36:/*LDC2*/ break; |
// case 0x37:/*LDC3*/ break; |
// case 0x38:/*SC*/ *(long*)ptr=r[rt]; r[rt]=1; break; |
case 0x38:/*SC*/ mem_write(s,4,ptr,r[rt]); r[rt]=1; break; |
// case 0x39:/*SWC1*/ break; |
// case 0x3a:/*SWC2*/ break; |
// case 0x3b:/*SWC3*/ break; |
// case 0x3d:/*SDC1*/ break; |
// case 0x3e:/*SDC2*/ break; |
// case 0x3f:/*SDC3*/ break; |
default: printf("ERROR2 address=0x%x opcode=0x%x\n", |
s->pc,opcode); s->wakeup=1; |
// exit(0); |
} |
s->pc_next+=branch|(lbranch==1)?imm_shift:0; |
s->skip=(lbranch==0); |
} |
|
void show_state(State *s) |
{ |
long i,j; |
for(i=0;i<4;++i) { |
printf("%2.2ld ",i*8); |
for(j=0;j<8;++j) { |
printf("%8.8lx ",s->r[i*8+j]); |
} |
printf("\n"); |
} |
printf("%8.8lx %8.8lx %8.8lx %8.8lx\n",s->pc,s->pc_next,s->hi,s->lo); |
j=s->pc; |
for(i=-4;i<=8;++i) { |
printf("%c",i==0?'*':' '); |
s->pc=j+i*4; |
cycle(s,10); |
} |
s->pc=j; |
} |
|
void do_debug(State *s) |
{ |
int ch; |
long i,j=0,watch=0,addr; |
s->pc_next=s->pc+4; |
s->skip=0; |
s->wakeup=0; |
show_state(s); |
for(;;) { |
if(watch) printf("0x%8.8lx=0x%8.8lx\n",watch,mem_read(s,4,watch)); |
printf("1=Debug 2=Trace 3=Step 4=BreakPt 5=Go 6=Memory "); |
printf("7=Watch 8=Jump 9=Quit> "); |
ch=getch(); |
printf("\n"); |
switch(ch) { |
case '1': case 'd': case ' ': cycle(s,0); show_state(s); break; |
case '2': case 't': cycle(s,0); printf("*"); cycle(s,10); break; |
case '3': case 's': |
printf("Count> "); |
scanf("%ld",&j); |
for(i=0;i<j;++i) cycle(s,0); |
show_state(s); |
break; |
case '4': case 'b': |
printf("Line> "); |
scanf("%lx",&j); |
break; |
case '5': case 'g': |
s->wakeup=0; |
while(s->wakeup==0) { |
if(s->pc==j) break; |
cycle(s,0); |
} |
show_state(s); |
break; |
case '6': case 'm': |
printf("Memory> "); |
scanf("%lx",&j); |
for(i=0;i<8;++i) { |
printf("%8.8lx ",mem_read(s,4,j+i*4)); |
} |
printf("\n"); |
break; |
case '7': case 'w': |
printf("Watch> "); |
scanf("%lx",&watch); |
break; |
case '8': case 'j': |
printf("Jump> "); |
scanf("%lx",&addr); |
s->pc=addr; |
s->pc_next=addr+4; |
show_state(s); |
break; |
case '9': case 'q': return; |
} |
} |
} |
/************************************************************/ |
|
int main(int argc,char *argv[]) |
{ |
State state,*s=&state; |
FILE *in; |
long bytes,index; |
printf("Plasma emulator\n"); |
memset(s,0,sizeof(State)); |
s->big_endian=0; |
s->mem=malloc(MEM_SIZE); |
if(argc<=1) { |
printf(" Usage: mlite file.exe\n"); |
printf(" mlite file.exe B {for big_endian}\n"); |
printf(" mlite file.exe DD {disassemble}\n"); |
printf(" mlite file.exe BD {disassemble big_endian}\n"); |
return 0; |
} |
in=fopen(argv[1],"rb"); |
if(in==NULL) { printf("Can't open file %s!\n",argv[1]); getch(); return(0); } |
bytes=fread(s->mem,1,MEM_SIZE,in); |
fclose(in); |
printf("Read %ld bytes.\n",bytes); |
if(argc==3&&argv[2][0]=='B') { |
printf("Big Endian\n"); |
s->big_endian=1; |
big_endian=1; |
} |
if(argc==3&&argv[2][0]=='S') { /*make big endian*/ |
printf("Big Endian\n"); |
for(index=0;index<bytes+3;index+=4) { |
*(unsigned long*)&s->mem[index]=htonl(*(unsigned long*)&s->mem[index]); |
} |
in=fopen("big.exe","wb"); |
fwrite(s->mem,bytes,1,in); |
fclose(in); |
return(0); |
} |
if(argc==3&&argv[2][1]=='D') { /*dump image*/ |
for(index=0;index<bytes;index+=4) { |
s->pc=index; |
cycle(s,10); |
} |
free(s->mem); |
return(0); |
} |
s->pc=0x0; |
do_debug(s); |
free(s->mem); |
return(0); |
} |
|
/tools/count.c
0,0 → 1,136
/*count.c*/ |
void putchar(int); |
int puts(const char*); |
|
char *name[]={ |
"","one","two","three","four","five","six","seven","eight","nine", |
"ten","eleven","twelve","thirteen","fourteen","fifteen", |
"sixteen","seventeen","eighteen","nineteen", |
"","ten","twenty","thirty","forty","fifty","sixty","seventy", |
"eighty","ninety" |
}; |
|
#ifndef MLITE |
int puts(const char *ptr) |
{ |
while(*ptr) { |
putchar(*ptr++); |
} |
return 0; |
} |
#endif |
|
#if 0 |
char *xtoa(unsigned long num) |
{ |
static char buf[12]; |
int i,digit; |
buf[8]=0; |
for(i=7;i>=0;--i) { |
digit=num&0xf; |
buf[i]=digit+(digit<10?'0':'A'-10); |
num>>=4; |
} |
return buf; |
} |
#endif |
|
char *itoa(unsigned long num) |
{ |
static char buf[12]; |
int i; |
buf[10]=0; |
for(i=9;i>=0;--i) { |
buf[i]=(char)((num%10)+'0'); |
num/=10; |
} |
return buf; |
} |
|
void number_text(unsigned long number) |
{ |
int digit; |
puts(itoa(number)); |
puts(": "); |
if(number>=1000000000) { |
digit=number/1000000000; |
puts(name[digit]); |
puts(" billion "); |
number%=1000000000; |
} |
if(number>=100000000) { |
digit=number/100000000; |
puts(name[digit]); |
puts(" hundred "); |
number%=100000000; |
if(number<1000000) { |
puts("million "); |
} |
} |
if(number>=20000000) { |
digit=number/10000000; |
puts(name[digit+20]); |
putchar(' '); |
number%=10000000; |
if(number<1000000) { |
puts("million "); |
} |
} |
if(number>=1000000) { |
digit=number/1000000; |
puts(name[digit]); |
puts(" million "); |
number%=1000000; |
} |
if(number>=100000) { |
digit=number/100000; |
puts(name[digit]); |
puts(" hundred "); |
number%=100000; |
if(number<1000) { |
puts("thousand "); |
} |
} |
if(number>=20000) { |
digit=number/10000; |
puts(name[digit+20]); |
putchar(' '); |
number%=10000; |
if(number<1000) { |
puts("thousand "); |
} |
} |
if(number>=1000) { |
digit=number/1000; |
puts(name[digit]); |
puts(" thousand "); |
number%=1000; |
} |
if(number>=100) { |
digit=number/100; |
puts(name[digit]); |
puts(" hundred "); |
number%=100; |
} |
if(number>=20) { |
digit=number/10; |
puts(name[digit+20]); |
putchar(' '); |
number%=10; |
} |
puts(name[number]); |
putchar('\r'); |
putchar('\n'); |
} |
|
void main() |
{ |
unsigned long number,i; |
puts("Mult by 3\r\n"); |
number=3; |
for(i=0;;++i) { |
number_text(number); |
number*=3; |
} |
} |
|
/tools/tracehex.c
0,0 → 1,176
/*********************************************************** |
| tracehex by Steve Rhoads 12/25/01 |
| This tool modifies trace files from the free VHDL simulator |
| http://www.symphonyeda.com/. |
| The binary numbers are converted to hex values. |
************************************************************/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <ctype.h> |
|
#define BUF_SIZE (1024*1024*4) |
#define LINE_SIZE 10000 |
|
char drop_char[10000]; |
|
int main(int argc, char *argv[]) |
{ |
FILE *file; |
char *buf,*ptr_in,*ptr_out,*line_store,*line; |
char *line_start,*source_start; |
int bytes,digits,value,isbinary,col,col_num,row,drop_cnt; |
int col_index,line_index,back_count,drop_start=0; |
int digits_length=0; |
(void)argc,argv; |
|
printf("tracehex\n"); |
|
/* Reading trace.txt */ |
file=fopen("trace.txt","r"); |
if(file==NULL) { |
printf("Can't open file\n"); |
return -1; |
} |
line_store=(char*)malloc(LINE_SIZE); |
line_store[0]=' '; |
line=line_store+1; |
buf=(char*)malloc(BUF_SIZE*2); |
if(buf==NULL) { |
printf("Can't malloc!\n"); |
return -1; |
} |
ptr_out=buf+BUF_SIZE; |
bytes=fread(buf,1,BUF_SIZE-1,file); |
buf[bytes]=0; |
fclose(file); |
|
digits=0; |
value=0; |
isbinary=0; |
col=0; |
col_num=0; |
row=0; |
line_start=ptr_out; |
source_start=buf; |
for(ptr_in=strstr(buf,"=");*ptr_in;++ptr_in) { |
++col; |
if(drop_start==0&&*ptr_in==' ') { |
for(drop_start=3;drop_start<30;++drop_start) { |
if(ptr_in[drop_start]!=' ') { |
break; |
} |
} |
for(;drop_start<30;++drop_start) { |
if(ptr_in[drop_start]==' ') { |
break; |
} |
} |
drop_start-=2; |
} |
if(col<4) { |
drop_char[col]=1; |
continue; |
} |
if(drop_start<=col&&col<=drop_start+2) { |
drop_char[col]=1; |
continue; |
} |
if(col<drop_start) { |
*ptr_out++=*ptr_in; |
continue; |
} |
|
/* convert binary number to hex */ |
if(isbinary&&(*ptr_in=='0'||*ptr_in=='1')) { |
value=value*2+*ptr_in-'0'; |
++digits; |
drop_char[col_num++]=1; |
} else if(isbinary&&*ptr_in=='Z') { |
value=1000; |
++digits; |
drop_char[col_num++]=1; |
} else if(isbinary&&(*ptr_in=='U'||*ptr_in=='X')) { |
value=10000; |
++digits; |
drop_char[col_num++]=1; |
} else { |
if(*ptr_in=='\n') { |
col=0; |
isbinary=0; |
++row; |
} |
if(isspace(*ptr_in)) { |
if(col>10) { |
isbinary=1; |
col_num=col; |
for(digits_length=1;!isspace(ptr_in[digits_length]);++digits_length) ; |
--digits_length; |
} |
} else { |
isbinary=0; |
} |
*ptr_out++=*ptr_in; |
digits=0; |
value=0; |
} |
/* convert every four binary digits to a hex digit */ |
if(digits&&(digits_length%4)==0) { |
drop_char[--col_num]=0; |
if(value<100) { |
*ptr_out++=value<10?value+'0':value-10+'A'; |
} else if(value<5000) { |
*ptr_out++='Z'; |
} else { |
*ptr_out++='U'; |
} |
digits=0; |
value=0; |
} |
--digits_length; |
} |
*ptr_out=0; |
|
/* now process the header */ |
file=fopen("trace2.txt","w"); |
col=0; |
line[0]=0; |
for(ptr_in=buf;*ptr_in;++ptr_in) { |
if(*ptr_in=='=') { |
break; |
} |
line[col++]=*ptr_in; |
if(*ptr_in=='\n') { |
line[col]=0; |
line_index=0; |
for(col_index=0;col_index<col;++col_index) { |
if(drop_char[col_index]) { |
back_count=0; |
while(line[line_index-back_count]!=' '&&back_count<10) { |
++back_count; |
} |
if(line[line_index-back_count-1]!=' ') { |
--back_count; |
} |
strcpy(line+line_index-back_count,line+line_index-back_count+1); |
} else { |
++line_index; |
} |
} |
fprintf(file,"%s",line); |
col=0; |
} |
} |
drop_cnt=0; |
for(col_index=13;col_index<sizeof(drop_char);++col_index) { |
if(drop_char[col_index]) { |
++drop_cnt; |
} |
} |
fprintf(file,"%s",buf+BUF_SIZE+drop_cnt); |
|
fclose(file); |
free(line_store); |
free(buf); |
return 0; |
} |
/tools/bintohex.c
0,0 → 1,55
/*bintohex by Steve Rhoads 5/29/02*/ |
#include <stdio.h> |
#include <string.h> |
|
#define BUF_SIZE (1024*1024) |
|
int main(int argc,char *argv[]) |
{ |
FILE *file; |
unsigned char *buf; |
unsigned long size,mem_size=1024*4,i,j,k,sum; |
char filename[80]; |
|
if(argc<2) { |
printf("usage: bintohex infile\n"); |
return -1; |
} |
file=fopen(argv[1],"rb"); |
if(file==NULL) { |
printf("Can't open %s\n",argv[1]); |
return -1; |
} |
buf=(unsigned char*)malloc(BUF_SIZE); |
memset(buf,0,BUF_SIZE); |
size=fread(buf,1,BUF_SIZE,file); |
mem_size=size; |
if(size>mem_size) { |
printf("FILE TOO LARGE!!!!!!!!!!!\n"); |
return -1; |
} |
fclose(file); |
strcpy(filename,"codeX.hex"); |
for(i=0;i<4;++i) { |
filename[4]='0'+i; |
file=fopen(filename,"wb"); |
for(j=0;i+j*4*16<mem_size;++j) { |
k=j*16; |
fprintf(file,":10%4.4x00",k); |
sum=0x10+(k>>8)+(k&0xff); |
for(k=0;k<16;++k) { |
fprintf(file,"%2.2x",buf[i+j*4*16+k*4]); |
sum+=buf[i+j*4*16+k*4]; |
} |
sum&=0xff; |
sum=0x100-sum; |
sum&=0xff; |
fprintf(file,"%2.2x\n",sum); |
} |
fprintf(file,":00000001ff\n"); |
fclose(file); |
} |
free(buf); |
return 0; |
} |
|
/tools/test.c
0,0 → 1,254
/*------------------------------------------------------------------- |
-- TITLE: Plasma CPU test code |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 4/21/01 |
-- FILENAME: test.c |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- The executable image of this file is used as input to the VHDL. |
-- |
-- This file must not contain any global or static data since |
-- there isn't a loader to relocate the .data segment and since |
-- having static data causes the opcodes to begin at a different |
-- location in the resulting executable file. |
-- |
-- Save the opcodes in "code.txt". |
-- |
-- The interrupt vector is set to address 0x30. |
--------------------------------------------------------------------*/ |
#ifdef MLITE |
#undef putchar |
// The Plasma CPU VHDL supports a virtual UART. All character writes |
// to address 0xffff will be stored in the file "output.txt". |
#define putchar(C) *(volatile unsigned char*)0xffff=(unsigned char)(C) |
void isr_enable(int); |
#else |
#define isr_enable(A) |
#endif |
|
char text[]="Testing the Plasma core.\n"; |
char buf[20]; |
int xyz=0xbadbeef; |
int abc; |
|
char *strcpy2(char *s, const char *t) |
{ |
char *tmp=s; |
while((int)(*s++=*t++)) ; |
return(tmp); |
} |
|
static void itoa2(long n, char *s, int base, long *digits) |
{ |
long i,j,sign; |
unsigned long n2; |
char number[20]; |
for(i=0;i<15;++i) { |
number[i]=' '; |
} |
number[15]=0; |
if(n>=0||base!=10) { |
sign=1; |
} else { |
sign=-1; |
} |
n2=n*sign; |
for(j=14;j>=0;--j) { |
i=n2%base; |
n2/=base; |
number[j]=i<10?'0'+i:'a'+i-10; |
if(n2==0&&15-j>=*digits) break; |
} |
if(sign==-1) { |
number[--j]='-'; |
} |
if(*digits==0||*digits<15-j) { |
strcpy2(s,&number[j]); |
*digits=15-j; |
} else { |
strcpy2(s,&number[15-*digits]); |
} |
} |
|
void print(long num,long base,long digits) |
{ |
char *ptr,buffer[128]; |
itoa2(num,buffer,base,&digits); |
ptr=buffer; |
while(*ptr) { |
putchar(*ptr++); /* Put the character out */ |
if(ptr[-1]=='\n') *--ptr='\r'; |
} |
} |
|
void print_hex(unsigned long num) |
{ |
long i; |
unsigned long j; |
for(i=28;i>=0;i-=4) { |
j=((num>>i)&0xf); |
if(j<10) putchar('0'+j); |
else putchar('a'-10+j); |
} |
} |
|
void print_string(char *p) |
{ |
int i; |
for(i=0;p[i];++i) { |
putchar(p[i]); |
} |
} |
|
int prime() |
{ |
int i,j; |
//show all prime numbers less than 1000 |
for(i=3;i<1000;i+=2) { |
for(j=3;j<i;j+=2) { |
if(i%j==0) { |
j=0; |
break; |
} |
} |
if(j) { |
print(i,10,0); |
putchar(' '); |
} |
} |
putchar('\n'); |
return 0; |
} |
|
int main2() |
{ |
long i,j; |
char char_buf[16]; |
short short_buf[16]; |
long long_buf[16]; |
|
//Uncomment to test interrupts |
// isr_enable(1); |
|
#if 1 |
//test shift |
j=0x12345678; |
for(i=0;i<32;++i) { |
print_hex(j>>i); |
putchar(' '); |
} |
putchar('\n'); |
j=0x92345678; |
for(i=0;i<32;++i) { |
print_hex(j>>i); |
putchar(' '); |
} |
putchar('\n'); |
j=0x12345678; |
for(i=0;i<32;++i) { |
print_hex(j<<i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
#endif |
|
#if 1 |
//test multiply and divide |
j=7; |
for(i=0;i<=10;++i) { |
print(j*i,10,0); |
putchar(' '); |
} |
putchar('\n'); |
j=0x321; |
for(i=0;i<=5;++i) { |
print_hex(j*(i+0x12345)); |
putchar(' '); |
} |
putchar('\n'); |
j=0x54321; |
for(i=0;i<=5;++i) { |
print_hex(j*(i+0x123)); |
putchar(' '); |
} |
putchar('\n'); |
j=0x12345; |
for(i=1;i<10;++i) { |
print_hex(j/i); |
putchar(' '); |
} |
putchar('\n'); |
for(i=1;i<10;++i) { |
print_hex(j%i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
#endif |
|
#if 1 |
//test addition and subtraction |
j=0x1234; |
for(i=0;i<10;++i) { |
print_hex(j+i); |
putchar(' '); |
} |
putchar('\n'); |
for(i=0;i<10;++i) { |
print_hex(j-i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
#endif |
|
#if 1 |
//test bit operations |
i=0x1234; |
j=0x4321; |
print_hex(i&j); |
putchar(' '); |
print_hex(i|j); |
putchar(' '); |
print_hex(i^j); |
putchar(' '); |
print_hex(~i); |
putchar(' '); |
print_hex(i+0x12); |
putchar(' '); |
print_hex(i-0x12); |
putchar('\n'); |
putchar('\n'); |
#endif |
|
#if 1 |
//test memory access |
for(i=0;i<10;++i) { |
char_buf[i]=i; |
short_buf[i]=i; |
long_buf[i]=i; |
} |
for(i=0;i<10;++i) { |
j=char_buf[i]; |
print(j,10,0); |
putchar(' '); |
j=short_buf[i]; |
print(j,10,0); |
putchar(' '); |
j=long_buf[i]; |
print(j,10,0); |
putchar('\n'); |
} |
putchar('\n'); |
#endif |
|
prime(); |
|
putchar('d'); putchar('o'); putchar('n'); putchar('e'); putchar('\n'); |
|
for(;;) ; |
} |
|
/tools/pi.c
0,0 → 1,23
/*Calculate the value of PI. Takes a long time!*/ |
void putchar(char); |
|
void print_num(unsigned long num) |
{ |
unsigned long digit,offset; |
for(offset=1000;offset;offset/=10) { |
digit=num/offset; |
putchar(digit+'0'); |
num-=digit*offset; |
} |
} |
|
long a=10000,b,c=56,d,e,f[57],g; |
void main() |
{ |
long a5=a/5; |
for(;b-c;) f[b++]=a5; |
for(;d=0,g=c*2;c-=14,print_num(e+d/a),e=d%a)for(b=c;d+=f[b]*a, |
f[b]=d%--g,d/=g--,--b;d*=b); |
putchar('\n'); |
} |
|
/vhdl/mlite_pack.vhd
0,0 → 1,590
--------------------------------------------------------------------- |
-- TITLE: Plasma Misc. Package |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/15/01 |
-- FILENAME: mlite_pack.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Data types, constants, and add functions needed for the Plasma CPU. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
|
package mlite_pack is |
constant ZERO : std_logic_vector(31 downto 0) := |
"00000000000000000000000000000000"; |
constant ONES : std_logic_vector(31 downto 0) := |
"11111111111111111111111111111111"; |
--make HIGH_Z equal to ZERO if compiler complains |
constant HIGH_Z : std_logic_vector(31 downto 0) := |
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; |
|
-- type alu_function_type is (alu_nothing, alu_add, alu_subtract, |
-- alu_less_than, alu_less_than_signed, |
-- alu_or, alu_and, alu_xor, alu_nor); |
subtype alu_function_type is std_logic_vector(3 downto 0); |
constant alu_nothing : alu_function_type := "0000"; |
constant alu_add : alu_function_type := "0001"; |
constant alu_subtract : alu_function_type := "0010"; |
constant alu_less_than : alu_function_type := "0011"; |
constant alu_less_than_signed : alu_function_type := "0100"; |
constant alu_or : alu_function_type := "0101"; |
constant alu_and : alu_function_type := "0110"; |
constant alu_xor : alu_function_type := "0111"; |
constant alu_nor : alu_function_type := "1000"; |
|
-- type shift_function_type is ( |
-- shift_nothing, shift_left_unsigned, |
-- shift_right_signed, do_right_unsigned); |
subtype shift_function_type is std_logic_vector(1 downto 0); |
constant shift_nothing : shift_function_type := "00"; |
constant shift_left_unsigned : shift_function_type := "01"; |
constant shift_right_signed : shift_function_type := "11"; |
constant shift_right_unsigned : shift_function_type := "10"; |
|
-- type mult_function_type is ( |
-- mult_nothing, mult_read_lo, mult_read_hi, mult_write_lo, |
-- mult_write_hi, mult_mult, mult_divide, mult_signed_divide); |
subtype mult_function_type is std_logic_vector(3 downto 0); |
constant mult_nothing : mult_function_type := "0000"; |
constant mult_read_lo : mult_function_type := "0001"; |
constant mult_read_hi : mult_function_type := "0010"; |
constant mult_write_lo : mult_function_type := "0011"; |
constant mult_write_hi : mult_function_type := "0100"; |
constant mult_mult : mult_function_type := "0101"; |
constant mult_signed_mult : mult_function_type := "0110"; |
constant mult_divide : mult_function_type := "0111"; |
constant mult_signed_divide : mult_function_type := "1000"; |
|
-- type a_source_type is (from_reg_source, from_imm10_6); |
subtype a_source_type is std_logic_vector(1 downto 0); |
constant a_from_reg_source : a_source_type := "00"; |
constant a_from_imm10_6 : a_source_type := "01"; |
constant a_from_pc : a_source_type := "10"; |
|
-- type b_source_type is (from_reg_target, from_imm, from_signed_imm); |
subtype b_source_type is std_logic_vector(1 downto 0); |
constant b_from_reg_target : b_source_type := "00"; |
constant b_from_imm : b_source_type := "01"; |
constant b_from_signed_imm : b_source_type := "10"; |
constant b_from_immX4 : b_source_type := "11"; |
|
-- type c_source_type is (from_null, from_alu, from_shift, |
-- from_mult, from_memory, from_pc, from_imm_shift16, |
-- from_reg_source_nez, from_reg_source_eqz); |
subtype c_source_type is std_logic_vector(2 downto 0); |
constant c_from_null : c_source_type := "000"; |
constant c_from_alu : c_source_type := "001"; |
constant c_from_shift : c_source_type := "001"; --same as alu |
constant c_from_mult : c_source_type := "001"; --same as alu |
constant c_from_memory : c_source_type := "010"; |
constant c_from_pc : c_source_type := "011"; |
constant c_from_pc_plus4 : c_source_type := "100"; |
constant c_from_imm_shift16: c_source_type := "101"; |
constant c_from_reg_sourcen: c_source_type := "110"; |
|
-- type pc_source_type is (from_inc4, from_opcode25_0, from_branch, from_lbranch); |
subtype pc_source_type is std_logic_vector(1 downto 0); |
constant from_inc4 : pc_source_type := "00"; |
constant from_opcode25_0 : pc_source_type := "01"; |
constant from_branch : pc_source_type := "10"; |
constant from_lbranch : pc_source_type := "11"; |
|
subtype branch_function_type is std_logic_vector(2 downto 0); |
constant branch_ltz : branch_function_type := "000"; |
constant branch_lez : branch_function_type := "001"; |
constant branch_eq : branch_function_type := "010"; |
constant branch_ne : branch_function_type := "011"; |
constant branch_gez : branch_function_type := "100"; |
constant branch_gtz : branch_function_type := "101"; |
constant branch_yes : branch_function_type := "110"; |
|
-- mode(32=1,16=2,8=3), signed, write |
subtype mem_source_type is std_logic_vector(3 downto 0); |
constant mem_fetch : mem_source_type := "0000"; |
constant mem_read32 : mem_source_type := "0100"; |
constant mem_write32 : mem_source_type := "0101"; |
constant mem_read16 : mem_source_type := "1000"; |
constant mem_read16s : mem_source_type := "1010"; |
constant mem_write16 : mem_source_type := "1001"; |
constant mem_read8 : mem_source_type := "1100"; |
constant mem_read8s : mem_source_type := "1110"; |
constant mem_write8 : mem_source_type := "1101"; |
|
function bv_to_integer(bv: in std_logic_vector) return integer; |
function bv_adder(a : in std_logic_vector(32 downto 0); |
b : in std_logic_vector(32 downto 0); |
do_add: in std_logic) return std_logic_vector; |
function bv_adder_lookahead( |
a : in std_logic_vector(32 downto 0); |
b : in std_logic_vector(32 downto 0); |
do_add: in std_logic) return std_logic_vector; |
function bv_negate(a : in std_logic_vector) return std_logic_vector; |
function bv_increment(a : in std_logic_vector(31 downto 2) |
) return std_logic_vector; |
function bv_inc6(a : in std_logic_vector |
) return std_logic_vector; |
|
-- For Altera |
COMPONENT lpm_add_sub |
GENERIC ( |
lpm_width : NATURAL; |
lpm_direction : STRING := "UNUSED"; |
lpm_type : STRING; |
lpm_hint : STRING); |
PORT ( |
dataa : IN STD_LOGIC_VECTOR (lpm_width-1 DOWNTO 0); |
add_sub : IN STD_LOGIC ; |
datab : IN STD_LOGIC_VECTOR (lpm_width-1 DOWNTO 0); |
result : OUT STD_LOGIC_VECTOR (lpm_width-1 DOWNTO 0)); |
END COMPONENT; |
|
-- For Altera |
COMPONENT lpm_ram_dp |
GENERIC ( |
lpm_width : NATURAL; |
lpm_widthad : NATURAL; |
rden_used : STRING; |
intended_device_family : STRING; |
lpm_indata : STRING; |
lpm_wraddress_control : STRING; |
lpm_rdaddress_control : STRING; |
lpm_outdata : STRING; |
use_eab : STRING; |
lpm_type : STRING); |
PORT ( |
wren : IN STD_LOGIC ; |
wrclock : IN STD_LOGIC ; |
q : OUT STD_LOGIC_VECTOR (lpm_width-1 DOWNTO 0); |
data : IN STD_LOGIC_VECTOR (lpm_width-1 DOWNTO 0); |
rdaddress : IN STD_LOGIC_VECTOR (lpm_widthad-1 DOWNTO 0); |
wraddress : IN STD_LOGIC_VECTOR (lpm_widthad-1 DOWNTO 0)); |
END COMPONENT; |
|
-- For Altera |
component LPM_RAM_DQ |
generic ( |
LPM_WIDTH : natural; -- MUST be greater than 0 |
LPM_WIDTHAD : natural; -- MUST be greater than 0 |
LPM_NUMWORDS : natural := 0; |
LPM_INDATA : string := "REGISTERED"; |
LPM_ADDRESS_CONTROL: string := "REGISTERED"; |
LPM_OUTDATA : string := "REGISTERED"; |
LPM_FILE : string := "UNUSED"; |
LPM_TYPE : string := "LPM_RAM_DQ"; |
USE_EAB : string := "OFF"; |
INTENDED_DEVICE_FAMILY : string := "UNUSED"; |
LPM_HINT : string := "UNUSED"); |
port ( |
DATA : in std_logic_vector(LPM_WIDTH-1 downto 0); |
ADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); |
INCLOCK : in std_logic := '0'; |
OUTCLOCK : in std_logic := '0'; |
WE : in std_logic; |
Q : out std_logic_vector(LPM_WIDTH-1 downto 0)); |
end component; |
|
-- For Xilinx |
component ramb4_s16_s16 |
port ( |
clka : in std_logic; |
rsta : in std_logic; |
addra : in std_logic_vector; |
dia : in std_logic_vector; |
ena : in std_logic; |
wea : in std_logic; |
doa : out std_logic_vector; |
|
clkb : in std_logic; |
rstb : in std_logic; |
addrb : in std_logic_vector; |
dib : in std_logic_vector; |
enb : in std_logic; |
web : in std_logic); |
end component; |
|
-- For Xilinx |
component reg_file_dp_ram |
port ( |
addra : IN std_logic_VECTOR(4 downto 0); |
addrb : IN std_logic_VECTOR(4 downto 0); |
clka : IN std_logic; |
clkb : IN std_logic; |
dinb : IN std_logic_VECTOR(31 downto 0); |
douta : OUT std_logic_VECTOR(31 downto 0); |
web : IN std_logic); |
end component; |
|
-- For Xilinx |
component reg_file_dp_ram_xc4000xla |
port ( |
A : IN std_logic_vector(4 DOWNTO 0); |
DI : IN std_logic_vector(31 DOWNTO 0); |
WR_EN : IN std_logic; |
WR_CLK : IN std_logic; |
DPRA : IN std_logic_vector(4 DOWNTO 0); |
SPO : OUT std_logic_vector(31 DOWNTO 0); |
DPO : OUT std_logic_vector(31 DOWNTO 0)); |
end component; |
|
component pc_next |
port(clk : in std_logic; |
reset_in : in std_logic; |
pc_new : in std_logic_vector(31 downto 2); |
take_branch : in std_logic; |
pause_in : in std_logic; |
opcode25_0 : in std_logic_vector(25 downto 0); |
pc_source : in pc_source_type; |
pc_out : out std_logic_vector(31 downto 0); |
pc_out_plus4 : out std_logic_vector(31 downto 0)); |
end component; |
|
component mem_ctrl |
generic(ACCURATE_TIMING : boolean := false); |
port(clk : in std_logic; |
reset_in : in std_logic; |
pause_in : in std_logic; |
nullify_op : in std_logic; |
address_pc : in std_logic_vector(31 downto 0); |
opcode_out : out std_logic_vector(31 downto 0); |
|
address_data : in std_logic_vector(31 downto 0); |
mem_source : in mem_source_type; |
data_write : in std_logic_vector(31 downto 0); |
data_read : out std_logic_vector(31 downto 0); |
pause_out : out std_logic; |
|
mem_address : out std_logic_vector(31 downto 0); |
mem_data_w : out std_logic_vector(31 downto 0); |
mem_data_r : in std_logic_vector(31 downto 0); |
mem_byte_sel : out std_logic_vector(3 downto 0); |
mem_write : out std_logic); |
end component; |
|
component control |
port(opcode : in std_logic_vector(31 downto 0); |
intr_signal : in std_logic; |
rs_index : out std_logic_vector(5 downto 0); |
rt_index : out std_logic_vector(5 downto 0); |
rd_index : out std_logic_vector(5 downto 0); |
imm_out : out std_logic_vector(15 downto 0); |
alu_func : out alu_function_type; |
shift_func : out shift_function_type; |
mult_func : out mult_function_type; |
branch_func : out branch_function_type; |
a_source_out : out a_source_type; |
b_source_out : out b_source_type; |
c_source_out : out c_source_type; |
pc_source_out: out pc_source_type; |
mem_source_out:out mem_source_type); |
end component; |
|
component reg_bank |
generic(memory_type : string := "TRI_PORT"); |
port(clk : in std_logic; |
reset_in : in std_logic; |
pause : in std_logic; |
rs_index : in std_logic_vector(5 downto 0); |
rt_index : in std_logic_vector(5 downto 0); |
rd_index : in std_logic_vector(5 downto 0); |
reg_source_out : out std_logic_vector(31 downto 0); |
reg_target_out : out std_logic_vector(31 downto 0); |
reg_dest_new : in std_logic_vector(31 downto 0); |
intr_enable : out std_logic); |
end component; |
|
component bus_mux |
port(imm_in : in std_logic_vector(15 downto 0); |
reg_source : in std_logic_vector(31 downto 0); |
a_mux : in a_source_type; |
a_out : out std_logic_vector(31 downto 0); |
|
reg_target : in std_logic_vector(31 downto 0); |
b_mux : in b_source_type; |
b_out : out std_logic_vector(31 downto 0); |
|
c_bus : in std_logic_vector(31 downto 0); |
c_memory : in std_logic_vector(31 downto 0); |
c_pc : in std_logic_vector(31 downto 0); |
c_pc_plus4 : in std_logic_vector(31 downto 0); |
c_mux : in c_source_type; |
reg_dest_out : out std_logic_vector(31 downto 0); |
|
branch_func : in branch_function_type; |
take_branch : out std_logic); |
end component; |
|
component alu |
generic(adder_type : string := "GENERIC"; |
alu_type : string := "GENERIC"); |
port(a_in : in std_logic_vector(31 downto 0); |
b_in : in std_logic_vector(31 downto 0); |
alu_function : in alu_function_type; |
c_alu : out std_logic_vector(31 downto 0)); |
end component; |
|
component shifter |
generic( shifter_type : string := "GENERIC" ); |
port(value : in std_logic_vector(31 downto 0); |
shift_amount : in std_logic_vector(4 downto 0); |
shift_func : in shift_function_type; |
c_shift : out std_logic_vector(31 downto 0)); |
end component; |
|
component mult |
generic ( |
adder_type : string := "GENERIC"; |
mult_type : string := "GENERIC"); |
port ( |
clk : in std_logic; |
a, b : in std_logic_vector(31 downto 0); |
mult_func : in mult_function_type; |
c_mult : out std_logic_vector(31 downto 0); |
pause_out : out std_logic); |
end component; |
|
component pipeline |
port(clk : in std_logic; |
reset : in std_logic; |
a_bus : in std_logic_vector(31 downto 0); |
a_busD : out std_logic_vector(31 downto 0); |
b_bus : in std_logic_vector(31 downto 0); |
b_busD : out std_logic_vector(31 downto 0); |
alu_func : in alu_function_type; |
alu_funcD : out alu_function_type; |
shift_func : in shift_function_type; |
shift_funcD : out shift_function_type; |
mult_func : in mult_function_type; |
mult_funcD : out mult_function_type; |
reg_dest : in std_logic_vector(31 downto 0); |
reg_destD : out std_logic_vector(31 downto 0); |
rd_index : in std_logic_vector(5 downto 0); |
rd_indexD : out std_logic_vector(5 downto 0); |
|
rs_index : in std_logic_vector(5 downto 0); |
rt_index : in std_logic_vector(5 downto 0); |
pc_source : in pc_source_type; |
mem_source : in mem_source_type; |
a_source : in a_source_type; |
b_source : in b_source_type; |
c_source : in c_source_type; |
c_bus : in std_logic_vector(31 downto 0); |
pause_any : in std_logic; |
pause_pipeline : out std_logic); |
end component; |
|
component mlite_cpu |
generic(memory_type : string := "ALTERA"; |
mult_type : string := "GENERIC"; |
shifter_type : string := "GENERIC"; |
pipeline_stages : natural := 3); |
port(clk : in std_logic; |
reset_in : in std_logic; |
intr_in : in std_logic; |
|
mem_address : out std_logic_vector(31 downto 0); |
mem_data_w : out std_logic_vector(31 downto 0); |
mem_data_r : in std_logic_vector(31 downto 0); |
mem_byte_sel: out std_logic_vector(3 downto 0); |
mem_write : out std_logic; |
mem_pause : in std_logic); |
end component; |
|
component ram |
generic(memory_type : string := "GENERIC"); |
port(clk : in std_logic; |
mem_byte_sel : in std_logic_vector(3 downto 0); |
mem_write : in std_logic; |
mem_address : in std_logic_vector(31 downto 0); |
mem_data_w : in std_logic_vector(31 downto 0); |
mem_data_r : out std_logic_vector(31 downto 0)); |
end component; --ram |
|
component uart |
generic(log_file : string := "UNUSED"); |
port(clk : in std_logic; |
reset : in std_logic; |
uart_sel : in std_logic; |
data : in std_logic_vector(7 downto 0); |
uart_read : in std_logic; |
uart_write : out std_logic; |
pause : out std_logic); |
end component; --uart |
|
component plasma |
generic(memory_type : string := "GENERIC"; |
log_file : string := "UNUSED"); |
port(clk_in : in std_logic; |
reset_in : in std_logic; |
intr_in : in std_logic; |
|
uart_read : in std_logic; |
uart_write : out std_logic; |
|
mem_address_out : out std_logic_vector(31 downto 0); |
mem_data : out std_logic_vector(31 downto 0); |
mem_byte_sel_out : out std_logic_vector(3 downto 0); |
mem_write_out : out std_logic; |
mem_pause_in : in std_logic); |
end component; --plasma |
|
component plasma_if |
generic(memory_type : string := "ALTERA"; |
log_file : string := "UNUSED"); |
port(clk_in : in std_logic; |
reset_n : in std_logic; |
uart_read : in std_logic; |
uart_write : out std_logic; |
|
address : out std_logic_vector(31 downto 0); |
data : out std_logic_vector(31 downto 0); |
we_n : out std_logic; |
oe_n : out std_logic; |
be_n : out std_logic_vector(3 downto 0); |
sram0_cs_n : out std_logic; |
sram1_cs_n : out std_logic); |
end component; --plasma_if |
|
end; --package mlite_pack |
|
package body mlite_pack is |
|
function bv_to_integer(bv: in std_logic_vector) return integer is |
variable result : integer; |
variable b : integer; |
begin |
result := 0; |
b := 0; |
for index in bv'range loop |
if bv(index) = '1' then |
b := 1; |
else |
b := 0; |
end if; |
result := result * 2 + b; |
end loop; |
return result; |
end; --function bv_to_integer |
|
|
function bv_adder(a : in std_logic_vector(32 downto 0); |
b : in std_logic_vector(32 downto 0); |
do_add: in std_logic) return std_logic_vector is |
variable carry_in : std_logic; |
variable bb : std_logic_vector(32 downto 0); |
variable result : std_logic_vector(32 downto 0); |
begin |
result := '0' & ZERO; |
if do_add = '1' then |
bb := b; |
carry_in := '0'; |
else |
bb := not b; |
carry_in := '1'; |
end if; |
for index in 0 to 32 loop |
result(index) := a(index) xor bb(index) xor carry_in; |
carry_in := (carry_in and (a(index) or bb(index))) or |
(a(index) and bb(index)); |
end loop; |
return result; |
end; --function |
|
|
function bv_adder_lookahead( |
a : in std_logic_vector(32 downto 0); |
b : in std_logic_vector(32 downto 0); |
do_add: in std_logic) return std_logic_vector is |
variable carry : std_logic_vector(32 downto 0); |
variable p, g : std_logic_vector(32 downto 0); |
variable bb : std_logic_vector(32 downto 0); |
variable result : std_logic_vector(32 downto 0); |
variable i : natural; |
begin |
carry := '0' & ZERO; |
if do_add = '1' then |
bb := b; |
carry(0) := '0'; |
else |
bb := not b; |
carry(0) := '1'; |
end if; |
|
p := a or bb; --propogate |
g := a and bb; --generate |
for index in 0 to 7 loop |
i := index*4; |
carry(i+1) := g(i) or |
(p(i) and carry(i)); |
i := index*4+1; |
carry(i+1) := g(i) or |
(p(i) and g(i-1)) or |
((p(i) and p(i-1)) and carry(i-1)); |
i := index*4+2; |
carry(i+1) := g(i) or |
(p(i) and g(i-1)) or |
(p(i) and p(i-1) and g(i-2)) or |
((p(i) and p(i-1) and p(i-2)) and carry(i-2)); |
i := index*4+3; |
carry(i+1) := g(i) or |
(p(i) and g(i-1)) or |
(p(i) and p(i-1) and g(i-2)) or |
(p(i) and p(i-1) and p(i-2) and g(i-3)) or |
(((p(i) and p(i-1)) and (p(i-2) and p(i-3))) |
and carry(i-3)); |
end loop; |
result := (a xor bb) xor carry; |
return result; |
end; --function |
|
|
function bv_negate(a : in std_logic_vector) return std_logic_vector is |
variable carry_in : std_logic; |
variable not_a : std_logic_vector(31 downto 0); |
variable result : std_logic_vector(31 downto 0); |
begin |
result := ZERO; |
not_a := not a; |
carry_in := '1'; |
for index in a'reverse_range loop |
result(index) := not_a(index) xor carry_in; |
carry_in := carry_in and not_a(index); |
end loop; |
return result; |
end; --function |
|
|
function bv_increment(a : in std_logic_vector(31 downto 2) |
) return std_logic_vector is |
variable carry_in : std_logic; |
variable result : std_logic_vector(31 downto 2); |
begin |
result := ZERO(31 downto 2); |
carry_in := '1'; |
for index in 2 to 31 loop |
result(index) := a(index) xor carry_in; |
carry_in := a(index) and carry_in; |
end loop; |
return result; |
end; --function |
|
|
function bv_inc6(a : in std_logic_vector |
) return std_logic_vector is |
variable carry_in : std_logic; |
variable result : std_logic_vector(5 downto 0); |
begin |
result := "000000"; |
carry_in := '1'; |
for index in 0 to 5 loop |
result(index) := a(index) xor carry_in; |
carry_in := a(index) and carry_in; |
end loop; |
return result; |
end; --function |
|
end; --package body |
|
|
/vhdl/mlite_cpu.vhd
0,0 → 1,341
--------------------------------------------------------------------- |
-- TITLE: Plasma CPU core |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/15/01 |
-- FILENAME: mlite_cpu.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- NOTE: MIPS(tm) and MIPS I(tm) are registered trademarks of MIPS |
-- Technologies. MIPS Technologies does not endorse and is not |
-- associated with this project. |
-- DESCRIPTION: |
-- Top level VHDL document that ties the nine other entities together. |
-- |
-- Executes all MIPS I(tm) opcodes but exceptions and non-aligned |
-- memory accesses. Based on information found in: |
-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich |
-- and "The Designer's Guide to VHDL" by Peter J. Ashenden |
-- |
-- The CPU is implemented as a two or three stage pipeline. |
-- An add instruction would take the following steps (see cpu.gif): |
-- Stage #1: |
-- 1. The "pc_next" entity passes the program counter (PC) to the |
-- "mem_ctrl" entity which fetches the opcode from memory. |
-- Stage #2: |
-- 2. "Mem_ctrl" passes the opcode to the "control" entity. |
-- 3. "Control" converts the 32-bit opcode to a 60-bit VLWI opcode |
-- and sends control signals to the other entities. |
-- 4. Based on the rs_index and rt_index control signals, "reg_bank" |
-- sends the 32-bit reg_source and reg_target to "bus_mux". |
-- 5. Based on the a_source and b_source control signals, "bus_mux" |
-- multiplexes reg_source onto a_bus and reg_target onto b_bus. |
-- Stage #3: |
-- 6. Based on the alu_func control signals, "alu" adds the values |
-- from a_bus and b_bus and places the result on c_bus. |
-- 7. Based on the c_source control signals, "bus_bux" multiplexes |
-- c_bus onto reg_dest. |
-- 8. Based on the rd_index control signal, "reg_bank" saves |
-- reg_dest into the correct register. |
-- |
-- All signals are active high. Writing to high memory where a(31)='1' |
-- takes five cycles to meet RAM address hold times. |
-- Addresses with a(31)='0' are assumed to be clocked and take three cycles. |
-- Here are the signals for writing a character to address 0xffff: |
-- |
-- intr_in mem_pause |
-- reset_in mem_write |
-- clk mem_byte_sel |
-- ns mem_address m_data_r m_data_w |
-- ============================================= |
-- 3000 1 0 0 0000002C A2820000 ZZZZZZZZ 0 0 0 (0 fetch write opcode) |
-- 3050 0 0 0 0000002C A2820000 ZZZZZZZZ 0 0 0 |
-- 3100 1 0 0 00000030 340A0041 ZZZZZZZZ 0 0 0 (1 execute write opcode) |
-- 3150 0 0 0 00000030 340A0041 ZZZZZZZZ 0 0 0 |
-- 3200 1 0 0 00000030 340A0041 ZZZZZZZZ 0 0 0 (2 calculating address) |
-- 3250 0 0 0 00000030 340A0041 ZZZZZZZZ 0 0 0 |
-- 3300 1 0 0 0000FFFF ZZZZZZZZ 6A6A6A6A 1 1 0 (3 writing value) |
-- 3350 0 0 0 0000FFFF ZZZZZZZZ 6A6A6A6A 1 1 0 |
-- 3400 1 0 0 00000034 340B0042 ZZZZZZZZ 0 0 0 |
-- 3450 0 0 0 00000034 340B0042 ZZZZZZZZ 0 0 0 |
-- |
-- Program: |
-- addr value opcode args |
-- =================================== |
-- 002c a2820000 sb $v0,0($s4) |
-- 0030 340a0041 li $t2,0x41 |
-- 0034 340b0042 li $t3,0x42 |
--------------------------------------------------------------------- |
library ieee; |
use work.mlite_pack.all; |
--library ieee, mlite_lib; |
--use mlite_lib.mlite_pack.all; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned.all; |
|
entity mlite_cpu is |
generic(memory_type : string := "GENERIC"; --DUAL_PORT_XILINX_XC4000XLA |
adder_type : string := "GENERIC"; --AREA_OPTIMIZED |
mult_type : string := "GENERIC"; --AREA_OPTIMIZED |
shifter_type : string := "GENERIC"; --AREA_OPTIMIZED |
alu_type : string := "GENERIC"; --AREA_OPTIMIZED |
pipeline_stages : natural := 3; |
accurate_timing : boolean := true); |
port(clk : in std_logic; |
reset_in : in std_logic; |
intr_in : in std_logic; |
|
mem_address : out std_logic_vector(31 downto 0); |
mem_data_w : out std_logic_vector(31 downto 0); |
mem_data_r : in std_logic_vector(31 downto 0); |
mem_byte_sel: out std_logic_vector(3 downto 0); |
mem_write : out std_logic; |
mem_pause : in std_logic); |
end; --entity mlite_cpu |
|
architecture logic of mlite_cpu is |
--When using a two stage pipeline "sigD <= sig". |
--When using a three stage pipeline "sigD <= sig when rising_edge(clk)", |
-- so sigD is delayed by one clock cycle. |
signal opcode : std_logic_vector(31 downto 0); |
signal rs_index : std_logic_vector(5 downto 0); |
signal rt_index : std_logic_vector(5 downto 0); |
signal rd_index : std_logic_vector(5 downto 0); |
signal rd_indexD : std_logic_vector(5 downto 0); |
signal reg_source : std_logic_vector(31 downto 0); |
signal reg_target : std_logic_vector(31 downto 0); |
signal reg_dest : std_logic_vector(31 downto 0); |
signal reg_destD : std_logic_vector(31 downto 0); |
signal a_bus : std_logic_vector(31 downto 0); |
signal a_busD : std_logic_vector(31 downto 0); |
signal b_bus : std_logic_vector(31 downto 0); |
signal b_busD : std_logic_vector(31 downto 0); |
signal c_bus : std_logic_vector(31 downto 0); |
signal c_alu : std_logic_vector(31 downto 0); |
signal c_shift : std_logic_vector(31 downto 0); |
signal c_mult : std_logic_vector(31 downto 0); |
signal c_memory : std_logic_vector(31 downto 0); |
signal imm : std_logic_vector(15 downto 0); |
signal pc : std_logic_vector(31 downto 0); |
signal pc_plus4 : std_logic_vector(31 downto 0); |
signal alu_func : alu_function_type; |
signal alu_funcD : alu_function_type; |
signal shift_func : shift_function_type; |
signal shift_funcD : shift_function_type; |
signal mult_func : mult_function_type; |
signal mult_funcD : mult_function_type; |
signal branch_func : branch_function_type; |
signal take_branch : std_logic; |
signal a_source : a_source_type; |
signal b_source : b_source_type; |
signal c_source : c_source_type; |
signal pc_source : pc_source_type; |
signal mem_source : mem_source_type; |
signal pause_mult : std_logic; |
signal pause_ctrl : std_logic; |
signal pause_pipeline : std_logic; |
signal pause_any : std_logic; |
signal pause_non_ctrl : std_logic; |
signal pause_bank : std_logic; |
signal nullify_op : std_logic; |
signal intr_enable : std_logic; |
signal intr_signal : std_logic; |
signal reset_reg : std_logic_vector(3 downto 0); |
signal reset : std_logic; |
begin --architecture |
|
pause_any <= (mem_pause or pause_ctrl) or (pause_mult or pause_pipeline); |
pause_non_ctrl <= (mem_pause or pause_mult) or pause_pipeline; |
pause_bank <= (mem_pause or pause_ctrl or pause_mult) and not pause_pipeline; |
nullify_op <= '1' when (pc_source = from_lbranch and take_branch = '0') |
or intr_signal = '1' |
else '0'; |
c_bus <= c_alu or c_shift or c_mult; |
reset <= '1' when reset_in = '1' or reset_reg /= "1111" else '0'; |
|
--synchronize reset and interrupt pins |
intr_proc: process(clk, reset_in, reset_reg, intr_in, intr_enable, |
pc_source, pc, pause_any) |
begin |
if reset_in = '1' then |
reset_reg <= "0000"; |
intr_signal <= '0'; |
elsif rising_edge(clk) then |
if reset_reg /= "1111" then |
reset_reg <= reset_reg + 1; |
end if; |
|
--don't try to interrupt a multi-cycle instruction |
if pause_any = '0' then |
if intr_in = '1' and intr_enable = '1' and |
pc_source = from_inc4 and pc(2) = '0' then |
--the epc will be backed up one opcode (pc-4) |
intr_signal <= '1'; |
else |
intr_signal <= '0'; |
end if; |
end if; |
|
end if; |
end process; |
|
u1_pc_next: pc_next PORT MAP ( |
clk => clk, |
reset_in => reset, |
take_branch => take_branch, |
pause_in => pause_any, |
pc_new => c_bus(31 downto 2), |
opcode25_0 => opcode(25 downto 0), |
pc_source => pc_source, |
pc_out => pc, |
pc_out_plus4 => pc_plus4); |
|
u2_mem_ctrl: mem_ctrl |
generic map (ACCURATE_TIMING => accurate_timing) |
PORT MAP ( |
clk => clk, |
reset_in => reset, |
pause_in => pause_non_ctrl, |
nullify_op => nullify_op, |
address_pc => pc, |
opcode_out => opcode, |
|
address_data => c_bus, |
mem_source => mem_source, |
data_write => reg_target, |
data_read => c_memory, |
pause_out => pause_ctrl, |
|
mem_address => mem_address, |
mem_data_w => mem_data_w, |
mem_data_r => mem_data_r, |
mem_byte_sel => mem_byte_sel, |
mem_write => mem_write); |
|
u3_control: control PORT MAP ( |
opcode => opcode, |
intr_signal => intr_signal, |
rs_index => rs_index, |
rt_index => rt_index, |
rd_index => rd_index, |
imm_out => imm, |
alu_func => alu_func, |
shift_func => shift_func, |
mult_func => mult_func, |
branch_func => branch_func, |
a_source_out => a_source, |
b_source_out => b_source, |
c_source_out => c_source, |
pc_source_out=> pc_source, |
mem_source_out=> mem_source); |
|
u4_reg_bank: reg_bank |
generic map(memory_type => memory_type) |
port map ( |
clk => clk, |
reset_in => reset, |
pause => pause_bank, |
rs_index => rs_index, |
rt_index => rt_index, |
rd_index => rd_indexD, |
reg_source_out => reg_source, |
reg_target_out => reg_target, |
reg_dest_new => reg_destD, |
intr_enable => intr_enable); |
|
u5_bus_mux: bus_mux port map ( |
imm_in => imm, |
reg_source => reg_source, |
a_mux => a_source, |
a_out => a_bus, |
|
reg_target => reg_target, |
b_mux => b_source, |
b_out => b_bus, |
|
c_bus => c_bus, |
c_memory => c_memory, |
c_pc => pc, |
c_pc_plus4 => pc_plus4, |
c_mux => c_source, |
reg_dest_out => reg_dest, |
|
branch_func => branch_func, |
take_branch => take_branch); |
|
u6_alu: alu |
generic map (adder_type => adder_type, |
alu_type => alu_type) |
port map ( |
a_in => a_busD, |
b_in => b_busD, |
alu_function => alu_funcD, |
c_alu => c_alu); |
|
u7_shifter: shifter |
generic map (shifter_type => shifter_type) |
port map ( |
value => b_busD, |
shift_amount => a_busD(4 downto 0), |
shift_func => shift_funcD, |
c_shift => c_shift); |
|
u8_mult: mult |
generic map (adder_type => adder_type, |
mult_type => mult_type) |
port map ( |
clk => clk, |
a => a_busD, |
b => b_busD, |
mult_func => mult_funcD, |
c_mult => c_mult, |
pause_out => pause_mult); |
|
pipeline2: if pipeline_stages <= 2 generate |
a_busD <= a_bus; |
b_busD <= b_bus; |
alu_funcD <= alu_func; |
shift_funcD <= shift_func; |
mult_funcD <= mult_func; |
rd_indexD <= rd_index; |
|
reg_destD <= reg_dest; |
pause_pipeline <= '0'; |
end generate; --pipeline2 |
|
pipeline3: if pipeline_stages >= 3 generate |
--When operating in three stage pipeline mode, the following signals |
--are delayed by one clock cycle: a_bus, b_bus, alu/shift/mult_func, |
--c_source, and rd_index. |
u9_pipeline: pipeline port map ( |
clk => clk, |
reset => reset, |
a_bus => a_bus, |
a_busD => a_busD, |
b_bus => b_bus, |
b_busD => b_busD, |
alu_func => alu_func, |
alu_funcD => alu_funcD, |
shift_func => shift_func, |
shift_funcD => shift_funcD, |
mult_func => mult_func, |
mult_funcD => mult_funcD, |
reg_dest => reg_dest, |
reg_destD => reg_destD, |
rd_index => rd_index, |
rd_indexD => rd_indexD, |
|
rs_index => rs_index, |
rt_index => rt_index, |
pc_source => pc_source, |
mem_source => mem_source, |
a_source => a_source, |
b_source => b_source, |
c_source => c_source, |
c_bus => c_bus, |
pause_any => pause_any, |
pause_pipeline => pause_pipeline); |
end generate; --pipeline3 |
|
end; --architecture logic |
|
/vhdl/reg_bank.vhd
0,0 → 1,368
--------------------------------------------------------------------- |
-- TITLE: Register Bank |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/2/01 |
-- FILENAME: reg_bank.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements a register bank with 32 registers that are 32-bits wide. |
-- There are two read-ports and one write port. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned.all; |
use work.mlite_pack.all; |
|
entity reg_bank is |
generic(memory_type : string := "GENERIC"); |
port(clk : in std_logic; |
reset_in : in std_logic; |
pause : in std_logic; |
rs_index : in std_logic_vector(5 downto 0); |
rt_index : in std_logic_vector(5 downto 0); |
rd_index : in std_logic_vector(5 downto 0); |
reg_source_out : out std_logic_vector(31 downto 0); |
reg_target_out : out std_logic_vector(31 downto 0); |
reg_dest_new : in std_logic_vector(31 downto 0); |
intr_enable : out std_logic); |
end; --entity reg_bank |
|
|
-------------------------------------------------------------------- |
-- The ram_block architecture attempts to use TWO dual-port memories. |
-- Different FPGAs and ASICs need different implementations. |
-- Choose one of the RAM implementations below. |
-- I need feedback on this section! |
-------------------------------------------------------------------- |
architecture ram_block of reg_bank is |
signal intr_enable_reg : std_logic; |
type ram_type is array(31 downto 0) of std_logic_vector(31 downto 0); |
|
--controls access to dual-port memories |
signal addr_a1, addr_a2, addr_b : std_logic_vector(4 downto 0); |
signal data_out1, data_out2 : std_logic_vector(31 downto 0); |
signal write_enable : std_logic; |
-- signal sig_false : std_logic := '0'; |
-- signal sig_true : std_logic := '1'; |
-- signal zero_sig : std_logic_vector(15 downto 0) := ZERO(15 downto 0); |
|
begin |
|
reg_proc: process(clk, rs_index, rt_index, rd_index, reg_dest_new, |
intr_enable_reg, data_out1, data_out2, reset_in, pause) |
begin |
--setup for first dual-port memory |
if rs_index = "101110" then --reg_epc CP0 14 |
addr_a1 <= "00000"; |
else |
addr_a1 <= rs_index(4 downto 0); |
end if; |
case rs_index is |
when "000000" => reg_source_out <= ZERO; |
when "101100" => reg_source_out <= ZERO(31 downto 1) & intr_enable_reg; |
when "111111" => --interrupt vector address = 0x3c |
reg_source_out <= ZERO(31 downto 8) & "00111100"; |
when others => reg_source_out <= data_out1; |
end case; |
|
--setup for second dual-port memory |
addr_a2 <= rt_index(4 downto 0); |
case rt_index is |
when "000000" => reg_target_out <= ZERO; |
when others => reg_target_out <= data_out2; |
end case; |
|
--setup second port (write port) for both dual-port memories |
if rd_index /= "000000" and rd_index /= "101100" and pause = '0' then |
write_enable <= '1'; |
else |
write_enable <= '0'; |
end if; |
if rd_index = "101110" then --reg_epc CP0 14 |
addr_b <= "00000"; |
else |
addr_b <= rd_index(4 downto 0); |
end if; |
|
if reset_in = '1' then |
intr_enable_reg <= '0'; |
elsif rising_edge(clk) then |
if rd_index = "101110" then --reg_epc CP0 14 |
intr_enable_reg <= '0'; --disable interrupts |
elsif rd_index = "101100" then |
intr_enable_reg <= reg_dest_new(0); |
end if; |
end if; |
|
intr_enable <= intr_enable_reg; |
end process; |
|
|
-------------------------------------------------------------- |
---- Pick only ONE of the dual-port RAM implementations below! |
-------------------------------------------------------------- |
|
-- synopsys synthesis_off |
|
-- Option #1 |
-- One tri-port RAM, two read-ports, one write-port |
-- 32 registers 32-bits wide |
tri_port_mem: |
if memory_type = "GENERIC" generate |
ram_proc: process(clk, addr_a1, addr_a2, addr_b, reg_dest_new, |
write_enable) |
variable tri_port_ram : ram_type; |
begin |
data_out1 <= tri_port_ram(conv_integer(addr_a1)); |
data_out2 <= tri_port_ram(conv_integer(addr_a2)); |
if rising_edge(clk) then |
if write_enable = '1' then |
tri_port_ram(conv_integer(addr_b)) := reg_dest_new; |
end if; |
end if; |
end process; |
end generate; --tri_port_mem |
|
|
-- Option #2 |
-- Two dual-port RAMs, each with one read-port and one write-port |
-- According to the Xilinx answers database record #4075 this |
-- architecture may cause Synplify to infer synchronous dual-port |
-- RAM using RAM16x1D. |
dual_port_mem: |
if memory_type = "DUAL_PORT" generate |
ram_proc2: process(clk, addr_a1, addr_a2, addr_b, reg_dest_new, |
write_enable) |
variable dual_port_ram1 : ram_type; |
variable dual_port_ram2 : ram_type; |
begin |
data_out1 <= dual_port_ram1(conv_integer(addr_a1)); |
data_out2 <= dual_port_ram2(conv_integer(addr_a2)); |
if rising_edge(clk) then |
if write_enable = '1' then |
dual_port_ram1(conv_integer(addr_b)) := reg_dest_new; |
dual_port_ram2(conv_integer(addr_b)) := reg_dest_new; |
end if; |
end if; |
end process; |
end generate; --dual_port_mem |
|
-- synopsys synthesis_on |
|
dual_port_mem_coregen: |
if memory_type = "DUAL_PORT_XILINX" generate |
|
reg_file_dp_ram_1: reg_file_dp_ram |
port map ( |
addra => addr_a1, |
addrb => addr_b, |
clka => clk, |
clkb => clk, |
dinb => reg_dest_new, |
douta => data_out1, |
web => write_enable); |
|
reg_file_dp_ram_2: reg_file_dp_ram |
port map ( |
addra => addr_a2, |
addrb => addr_b, |
clka => clk, |
clkb => clk, |
dinb => reg_dest_new, |
douta => data_out2, |
web => write_enable); |
|
end generate; --dual_port_mem |
|
dual_port_mem_xc4000xla: if memory_type = "DUAL_PORT_XILINX_XC4000XLA" generate |
|
reg_file_dp_ram_1: reg_file_dp_ram_xc4000xla |
port map ( |
A => addr_b, |
DI => reg_dest_new, |
WR_EN => write_enable, |
WR_CLK => clk, |
DPRA => addr_a1, |
SPO => open, |
DPO => data_out1); |
|
reg_file_dp_ram_2: reg_file_dp_ram_xc4000xla |
port map ( |
A => addr_b, |
DI => reg_dest_new, |
WR_EN => write_enable, |
WR_CLK => clk, |
DPRA => addr_a2, |
SPO => open, |
DPO => data_out2); |
|
end generate; --dual_port_mem |
|
-- Option #3 |
-- Generic Two-Port Synchronous RAM |
-- generic_tpram can be obtained from: |
-- http://www.opencores.org/cvsweb.shtml/generic_memories/ |
-- Supports ASICs (Artisan, Avant, and Virage) and Xilinx FPGA |
-- generic_mem: |
-- if memory_type = "OPENCORES_MEM" generate |
-- bank1 : generic_tpram port map ( |
-- clk_a => clk, |
-- rst_a => '0', |
-- ce_a => '1', |
-- we_a => '0', |
-- oe_a => '1', |
-- addr_a => addr_a1, |
-- di_a => ZERO, |
-- do_a => data_out1, |
-- |
-- clk_b => clk, |
-- rst_b => '0', |
-- ce_b => '1', |
-- we_b => write_enable, |
-- oe_b => '0', |
-- addr_b => addr_b, |
-- di_a => reg_dest_new); |
-- |
-- bank2 : generic_tpram port map ( |
-- clk_a => clk, |
-- rst_a => '0', |
-- ce_a => '1', |
-- we_a => '0', |
-- oe_a => '1', |
-- addr_a => addr_a2, |
-- di_a => ZERO, |
-- do_a => data_out2, |
-- |
-- clk_b => clk, |
-- rst_b => '0', |
-- ce_b => '1', |
-- we_b => write_enable, |
-- oe_b => '0', |
-- addr_b => addr_b, |
-- di_a => reg_dest_new); |
-- end generate; --generic_mem |
|
|
-- Option #4 |
-- Xilinx mode using four 16x16 banks |
-- xilinx_mem: |
-- if memory_type = "XILINX" generate |
-- bank1_high: ramb4_s16_s16 port map ( |
-- clka => clk, |
-- rsta => sig_false, |
-- addra => addr_a1, |
-- dia => zero_sig, |
-- ena => sig_true, |
-- wea => sig_false, |
-- doa => data_out1(31 downto 16), |
-- |
-- clkb => clk, |
-- rstb => sig_false, |
-- addrb => addr_b, |
-- dib => reg_dest_new(31 downto 16), |
-- enb => sig_true, |
-- web => write_enable); |
-- |
-- bank1_low: ramb4_s16_s16 port map ( |
-- clka => clk, |
-- rsta => sig_false, |
-- addra => addr_a1, |
-- dia => zero_sig, |
-- ena => sig_true, |
-- wea => sig_false, |
-- doa => data_out1(15 downto 0), |
-- |
-- clkb => clk, |
-- rstb => sig_false, |
-- addrb => addr_b, |
-- dib => reg_dest_new(15 downto 0), |
-- enb => sig_true, |
-- web => write_enable); |
-- |
-- bank2_high: ramb4_s16_s16 port map ( |
-- clka => clk, |
-- rsta => sig_false, |
-- addra => addr_a2, |
-- dia => zero_sig, |
-- ena => sig_true, |
-- wea => sig_false, |
-- doa => data_out2(31 downto 16), |
-- |
-- clkb => clk, |
-- rstb => sig_false, |
-- addrb => addr_b, |
-- dib => reg_dest_new(31 downto 16), |
-- enb => sig_true, |
-- web => write_enable); |
-- |
-- bank2_low: ramb4_s16_s16 port map ( |
-- clka => clk, |
-- rsta => sig_false, |
-- addra => addr_a2, |
-- dia => zero_sig, |
-- ena => sig_true, |
-- wea => sig_false, |
-- doa => data_out2(15 downto 0), |
-- |
-- clkb => clk, |
-- rstb => sig_false, |
-- addrb => addr_b, |
-- dib => reg_dest_new(15 downto 0), |
-- enb => sig_true, |
-- web => write_enable); |
-- end generate; --xilinx_mem |
|
|
-- Option #5 |
-- Altera LPM_RAM_DP |
-- Xilinx users may need to comment out this section!!! |
altera_mem: |
if memory_type = "ALTERA" generate |
lpm_ram_dp_component1 : lpm_ram_dp |
GENERIC MAP ( |
lpm_width => 32, |
lpm_widthad => 5, |
rden_used => "FALSE", |
intended_device_family => "UNUSED", |
lpm_indata => "REGISTERED", |
lpm_wraddress_control => "REGISTERED", |
lpm_rdaddress_control => "UNREGISTERED", |
lpm_outdata => "UNREGISTERED", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DP" |
) |
PORT MAP ( |
wren => write_enable, |
wrclock => clk, |
data => reg_dest_new, |
rdaddress => addr_a1, |
wraddress => addr_b, |
q => data_out1 |
); |
lpm_ram_dp_component2 : lpm_ram_dp |
GENERIC MAP ( |
lpm_width => 32, |
lpm_widthad => 5, |
rden_used => "FALSE", |
intended_device_family => "UNUSED", |
lpm_indata => "REGISTERED", |
lpm_wraddress_control => "REGISTERED", |
lpm_rdaddress_control => "UNREGISTERED", |
lpm_outdata => "UNREGISTERED", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DP" |
) |
PORT MAP ( |
wren => write_enable, |
wrclock => clk, |
data => reg_dest_new, |
rdaddress => addr_a2, |
wraddress => addr_b, |
q => data_out2 |
); |
end generate; --altera_mem |
|
end; --architecture ram_block |
|
/vhdl/pipeline.vhd
0,0 → 1,123
--------------------------------------------------------------------- |
-- TITLE: Pipeline |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 6/24/02 |
-- FILENAME: pipeline.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Controls the three stage pipeline by delaying the signals: |
-- a_bus, b_bus, alu/shift/mult_func, c_source, and rs_index. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
--Note: sigD <= sig after rising_edge(clk) |
entity pipeline is |
port(clk : in std_logic; |
reset : in std_logic; |
a_bus : in std_logic_vector(31 downto 0); |
a_busD : out std_logic_vector(31 downto 0); |
b_bus : in std_logic_vector(31 downto 0); |
b_busD : out std_logic_vector(31 downto 0); |
alu_func : in alu_function_type; |
alu_funcD : out alu_function_type; |
shift_func : in shift_function_type; |
shift_funcD : out shift_function_type; |
mult_func : in mult_function_type; |
mult_funcD : out mult_function_type; |
reg_dest : in std_logic_vector(31 downto 0); |
reg_destD : out std_logic_vector(31 downto 0); |
rd_index : in std_logic_vector(5 downto 0); |
rd_indexD : out std_logic_vector(5 downto 0); |
|
rs_index : in std_logic_vector(5 downto 0); |
rt_index : in std_logic_vector(5 downto 0); |
pc_source : in pc_source_type; |
mem_source : in mem_source_type; |
a_source : in a_source_type; |
b_source : in b_source_type; |
c_source : in c_source_type; |
c_bus : in std_logic_vector(31 downto 0); |
pause_any : in std_logic; |
pause_pipeline : out std_logic); |
end; --entity pipeline |
|
architecture logic of pipeline is |
signal rd_index_reg : std_logic_vector(5 downto 0); |
signal reg_dest_reg : std_logic_vector(31 downto 0); |
signal reg_dest_delay : std_logic_vector(31 downto 0); |
signal c_source_reg : c_source_type; |
signal pause_enable_reg : std_logic; |
begin |
|
--When operating in three stage pipeline mode, the following signals |
--are delayed by one clock cycle: a_bus, b_bus, alu/shift/mult_func, |
--c_source, and rd_index. |
pipeline3: process(clk, reset, a_bus, b_bus, alu_func, shift_func, mult_func, |
rd_index, rd_index_reg, pause_any, pause_enable_reg, |
rs_index, rt_index, |
pc_source, mem_source, a_source, b_source, c_source, c_source_reg, |
reg_dest, reg_dest_reg, reg_dest_delay, c_bus) |
variable pause_mult_clock : std_logic; |
variable freeze_pipeline : std_logic; |
begin |
if (pc_source /= from_inc4 and pc_source /= from_opcode25_0) or |
mem_source /= mem_fetch or |
(mult_func = mult_read_lo or mult_func = mult_read_hi) then |
pause_mult_clock := '1'; |
else |
pause_mult_clock := '0'; |
end if; |
|
freeze_pipeline := not (pause_mult_clock and pause_enable_reg) and pause_any; |
pause_pipeline <= pause_mult_clock and pause_enable_reg; |
rd_indexD <= rd_index_reg; |
|
if c_source_reg = c_from_alu then |
reg_dest_delay <= c_bus; --delayed by 1 clock cycle via a_busD & b_busD |
else |
reg_dest_delay <= reg_dest_reg; --need to delay 1 clock cycle from reg_dest |
end if; |
reg_destD <= reg_dest_delay; |
|
if reset = '1' then |
pause_enable_reg <= '1'; |
rd_index_reg <= "000000"; |
elsif rising_edge(clk) then |
if freeze_pipeline = '0' then |
if (rs_index = "000000" or rs_index /= rd_index_reg) or |
(a_source /= a_from_reg_source or pause_enable_reg = '0') then |
a_busD <= a_bus; |
else |
a_busD <= reg_dest_delay; --rs from previous operation (bypass stage) |
end if; |
|
if (rt_index = "000000" or rt_index /= rd_index_reg) or |
(b_source /= b_from_reg_target or pause_enable_reg = '0') then |
b_busD <= b_bus; |
else |
b_busD <= reg_dest_delay; --rt from previous operation |
end if; |
|
alu_funcD <= alu_func; |
shift_funcD <= shift_func; |
mult_funcD <= mult_func; |
reg_dest_reg <= reg_dest; |
c_source_reg <= c_source; |
rd_index_reg <= rd_index; |
end if; |
|
if pause_enable_reg = '0' and pause_any = '0' then |
pause_enable_reg <= '1'; --enable pause_pipeline |
elsif pause_mult_clock = '1' then |
pause_enable_reg <= '0'; --disable pause_pipeline |
end if; |
end if; |
|
end process; --pipeline3 |
|
end; --logic |
|
/vhdl/mult.vhd
0,0 → 1,538
--------------------------------------------------------------------- |
-- TITLE: Multiplication and Division Unit |
-- AUTHORS: Steve Rhoads (rhoadss@yahoo.com) |
-- Matthias Gruenewald |
-- DATE CREATED: 1/31/01 |
-- FILENAME: mult.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the multiplication and division unit. |
-- Division takes 32 clock cycles. |
-- Multiplication normally takes 16 clock cycles. |
-- if b <= 0xffff then mult in 8 cycles. |
-- if b <= 0xff then mult in 4 cycles. |
-- |
-- For multiplication set reg_b = 0x00000000 & b. The 64-bit result |
-- will be in reg_b. The lower bits of reg_b contain the upper |
-- bits of b that have not yet been multiplied. For 16 clock cycles |
-- shift reg_b two bits to the right. Use the lowest two bits of reg_b |
-- to multiply by two bits at a time and add the result to the upper |
-- 32-bits of reg_b (using C syntax): |
-- reg_b = (reg_b >> 2) + (((reg_b & 3) * reg_a) << 32); |
-- |
-- For division set reg_b = '0' & b & 30_ZEROS. The answer will be |
-- in answer_reg and the remainder in reg_a. For 32 clock cycles |
-- (using C syntax): |
-- answer_reg = (answer_reg << 1); |
-- if (reg_a >= reg_b) { |
-- answer_reg += 1; |
-- reg_a -= reg_b; |
-- } |
-- reg_b = reg_b >> 1; |
--------------------------------------------------------------------- |
--library ieee, MLITE_LIB; |
--use MLITE_LIB.all; |
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned.all; |
use IEEE.std_logic_arith.all; |
use work.mlite_pack.all; |
|
entity mult is |
generic(adder_type : string := "GENERIC"; |
mult_type : string := "GENERIC"); |
port(clk : in std_logic; |
a, b : in std_logic_vector(31 downto 0); |
mult_func : in mult_function_type; |
c_mult : out std_logic_vector(31 downto 0); |
pause_out : out std_logic); |
end; --entity mult |
|
architecture logic of mult is |
|
-- type mult_function_type is ( |
-- mult_nothing, mult_read_lo, mult_read_hi, mult_write_lo, |
-- mult_write_hi, mult_mult, mult_divide, mult_signed_divide); |
signal do_mult_reg : std_logic; |
signal do_signed_reg : std_logic; |
signal count_reg : std_logic_vector(5 downto 0); |
signal reg_a : std_logic_vector(31 downto 0); |
signal reg_b : std_logic_vector(63 downto 0); |
signal answer_reg : std_logic_vector(31 downto 0); |
signal aa, bb : std_logic_vector(33 downto 0); |
signal sum : std_logic_vector(33 downto 0); |
signal sum2 : std_logic_vector(67 downto 0); |
signal reg_a_times3 : std_logic_vector(33 downto 0); |
signal sign_extend_sig : std_logic; |
|
--Used in Xilinx tri-state area optimizated version |
signal SUB_Y, A_PROCESSED, B_PROCESSED, A_REG, B_REG : std_logic_vector(31 downto 0); |
signal DIV_Y, DIV_Y_IN, DIV_Y_IN_CALC, DIV_Y_IN_INIT, Y_IN, Y_IN2, MULT_Y, Y : std_logic_vector(63 downto 0) := (others => '0'); |
signal SAVE_Y, SAVE_DIV_Y, MULT_ND, MULT_RDY, DO_SIGNED, DIV_ND : std_logic; |
signal DIV_COUNT, INVERT_A, INVERT_B, INVERT_Y, DIV_RDY : std_logic; |
signal DIV_COUNTER : std_logic_vector(4 downto 0); |
signal PAUSE_IN, SAVE_PAUSE, PAUSE : std_logic := '0'; |
signal MULT_RFD : std_logic; |
signal a_temp_sig, a_neg_sig, b_neg_sig : std_logic_vector(31 downto 0); |
signal b_temp_sig : std_logic_vector(63 downto 0); |
signal a_msb, b_msb : std_logic; |
signal answer_temp_sig : std_logic_vector(31 downto 0); |
signal aa_select : std_logic_vector(3 downto 0); |
signal bb_select : std_logic_vector(1 downto 0); |
signal a_select : std_logic_vector(4 downto 0); |
signal b_select : std_logic_vector(11 downto 0); |
signal answer_select : std_logic_vector(2 downto 0); |
|
begin |
|
--sum = aa + bb |
generic_adder: if adder_type = "GENERIC" generate |
sum <= (aa + bb) when do_mult_reg = '1' else |
(aa - bb); |
end generate; --generic_adder |
|
--For Altera: sum = aa + bb |
lpm_adder: if adder_type = "ALTERA" generate |
lpm_add_sub_component : lpm_add_sub |
GENERIC MAP ( |
lpm_width => 34, |
lpm_direction => "UNUSED", |
lpm_type => "LPM_ADD_SUB", |
lpm_hint => "ONE_INPUT_IS_CONSTANT=NO" |
) |
PORT MAP ( |
dataa => aa, |
add_sub => do_mult_reg, |
datab => bb, |
result => sum |
); |
end generate; --lpm_adder |
|
-- Negate signals |
a_neg_sig <= bv_negate(a); |
b_neg_sig <= bv_negate(b); |
sign_extend_sig <= do_signed_reg and do_mult_reg; |
|
-- Result |
c_mult <= reg_b(31 downto 0) when mult_func=mult_read_lo else |
reg_b(63 downto 32) when mult_func=mult_read_hi else |
ZERO; |
|
|
GENERIC_MULT: if MULT_TYPE="GENERIC" generate |
|
--multiplication/division unit |
mult_proc: process(clk, a, b, mult_func, |
do_mult_reg, do_signed_reg, count_reg, |
reg_a, reg_b, answer_reg, sum, reg_a_times3) |
variable do_mult_temp : std_logic; |
variable do_signed_temp : std_logic; |
variable count_temp : std_logic_vector(5 downto 0); |
variable a_temp : std_logic_vector(31 downto 0); |
variable b_temp : std_logic_vector(63 downto 0); |
variable answer_temp : std_logic_vector(31 downto 0); |
variable start : std_logic; |
variable do_write : std_logic; |
variable do_hi : std_logic; |
variable sign_extend : std_logic; |
|
begin |
do_mult_temp := do_mult_reg; |
do_signed_temp := do_signed_reg; |
count_temp := count_reg; |
a_temp := reg_a; |
b_temp := reg_b; |
answer_temp := answer_reg; |
sign_extend := do_signed_reg and do_mult_reg; |
start := '0'; |
do_write := '0'; |
do_hi := '0'; |
|
case mult_func is |
when mult_read_lo => |
when mult_read_hi => |
do_hi := '1'; |
when mult_write_lo => |
do_write := '1'; |
when mult_write_hi => |
do_write := '1'; |
do_hi := '1'; |
when mult_mult => |
start := '1'; |
do_mult_temp := '1'; |
do_signed_temp := '0'; |
when mult_signed_mult => |
start := '1'; |
do_mult_temp := '1'; |
do_signed_temp := '1'; |
when mult_divide => |
start := '1'; |
do_mult_temp := '0'; |
do_signed_temp := '0'; |
when mult_signed_divide => |
start := '1'; |
do_mult_temp := '0'; |
do_signed_temp := a(31) xor b(31); |
when others => |
end case; |
|
if start = '1' then |
count_temp := "000000"; |
answer_temp := ZERO; |
if do_mult_temp = '0' then |
b_temp(63) := '0'; |
if mult_func /= mult_signed_divide or a(31) = '0' then |
a_temp := a; |
else |
a_temp := a_neg_sig; |
end if; |
if mult_func /= mult_signed_divide or b(31) = '0' then |
b_temp(62 downto 31) := b; |
else |
b_temp(62 downto 31) := b_neg_sig; |
end if; |
b_temp(30 downto 0) := ZERO(30 downto 0); |
else --multiply |
if do_signed_temp = '0' or b(31) = '0' then |
a_temp := a; |
b_temp(31 downto 0) := b; |
else |
a_temp := a_neg_sig; |
b_temp(31 downto 0) := b_neg_sig; |
end if; |
b_temp(63 downto 32) := ZERO; |
end if; |
elsif do_write = '1' then |
if do_hi = '0' then |
b_temp(31 downto 0) := a; |
else |
b_temp(63 downto 32) := a; |
end if; |
end if; |
|
if do_mult_reg = '0' then --division |
aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a; |
bb <= reg_b(33 downto 0); |
else --multiplication two-bits at a time |
case reg_b(1 downto 0) is |
when "00" => |
aa <= "00" & ZERO; |
when "01" => |
aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a; |
when "10" => |
aa <= (reg_a(31) and sign_extend) & reg_a & '0'; |
when others => |
aa <= reg_a_times3; |
end case; |
bb <= (reg_b(63) and sign_extend) & (reg_b(63) and sign_extend) & reg_b(63 downto 32); |
end if; |
|
if count_reg(5) = '0' and start = '0' then |
count_temp := bv_inc6(count_reg); |
if do_mult_reg = '0' then --division |
answer_temp(31 downto 1) := answer_reg(30 downto 0); |
if reg_b(63 downto 32) = ZERO and sum(32) = '0' then |
a_temp := sum(31 downto 0); --aa=aa-bb; |
answer_temp(0) := '1'; |
else |
answer_temp(0) := '0'; |
end if; |
if count_reg /= "011111" then |
b_temp(62 downto 0) := reg_b(63 downto 1); |
else --done with divide |
b_temp(63 downto 32) := a_temp; |
if do_signed_reg = '0' then |
b_temp(31 downto 0) := answer_temp; |
else |
b_temp(31 downto 0) := bv_negate(answer_temp); |
end if; |
end if; |
else -- mult_mode |
b_temp(63 downto 30) := sum; |
b_temp(29 downto 0) := reg_b(31 downto 2); |
if count_reg = "001000" and sign_extend = '0' and --early stop |
reg_b(15 downto 0) = ZERO(15 downto 0) then |
count_temp := "111111"; |
b_temp(31 downto 0) := reg_b(47 downto 16); |
end if; |
if count_reg = "000100" and sign_extend = '0' and --early stop |
reg_b(23 downto 0) = ZERO(23 downto 0) then |
count_temp := "111111"; |
b_temp(31 downto 0) := reg_b(55 downto 24); |
end if; |
count_temp(5) := count_temp(4); |
end if; |
end if; |
|
if rising_edge(clk) then |
do_mult_reg <= do_mult_temp; |
do_signed_reg <= do_signed_temp; |
count_reg <= count_temp; |
reg_a <= a_temp; |
reg_b <= b_temp; |
answer_reg <= answer_temp; |
if start = '1' then |
reg_a_times3 <= ((a_temp(31) and do_signed_temp) & a_temp & '0') + |
((a_temp(31) and do_signed_temp) & (a_temp(31) and do_signed_temp) & a_temp); |
end if; |
end if; |
|
if count_reg(5) = '0' and mult_func /= mult_nothing and start = '0' then |
pause_out <= '1'; |
else |
pause_out <= '0'; |
end if; |
|
end process; |
|
end generate; |
|
|
AREA_OPTIMIZED_MULT: if MULT_TYPE="AREA_OPTIMIZED" generate |
--Xilinx Tristate size optimization by Matthias Gruenewald |
|
--multiplication/division unit |
mult_proc: process(a, b, clk, count_reg, do_mult_reg, do_signed_reg, mult_func, reg_b, sum) |
variable do_mult_temp : std_logic; |
variable do_signed_temp : std_logic; |
variable count_temp : std_logic_vector(5 downto 0); |
variable start : std_logic; |
variable do_write : std_logic; |
variable do_hi : std_logic; |
variable sign_extend : std_logic; |
|
begin |
do_mult_temp := do_mult_reg; |
do_signed_temp := do_signed_reg; |
count_temp := count_reg; |
sign_extend := do_signed_reg and do_mult_reg; |
sign_extend_sig <= sign_extend; |
start := '0'; |
do_write := '0'; |
do_hi := '0'; |
a_select <= (others => '0'); |
b_select <= (others => '0'); |
aa_select <= (others => '0'); |
bb_select <= (others => '0'); |
answer_select <= (others => '0'); |
|
case mult_func is |
when mult_read_lo => |
when mult_read_hi => |
do_hi := '1'; |
when mult_write_lo => |
do_write := '1'; |
when mult_write_hi => |
do_write := '1'; |
do_hi := '1'; |
when mult_mult => |
start := '1'; |
do_mult_temp := '1'; |
do_signed_temp := '0'; |
when mult_signed_mult => |
start := '1'; |
do_mult_temp := '1'; |
do_signed_temp := '1'; |
when mult_divide => |
start := '1'; |
do_mult_temp := '0'; |
do_signed_temp := '0'; |
when mult_signed_divide => |
start := '1'; |
do_mult_temp := '0'; |
do_signed_temp := a(31) xor b(31); |
when others => |
end case; |
|
if start = '1' then |
count_temp := "000000"; |
answer_select(0)<='1'; |
--answer_temp := ZERO; |
if do_mult_temp = '0' then |
--b_temp(63) := '0'; |
if mult_func /= mult_signed_divide or a(31) = '0' then |
a_select(0) <= '1'; |
--a_temp := a; |
else |
a_select(1) <= '1'; |
--a_temp := a_neg; |
end if; |
if mult_func /= mult_signed_divide or b(31) = '0' then |
b_select(0) <= '1'; |
--b_temp(62 downto 31) := b; |
else |
b_select(1) <= '1'; |
--b_temp(62 downto 31) := b_neg; |
end if; |
--b_temp(30 downto 0) := ZERO(30 downto 0); |
else --multiply |
if do_signed_temp = '0' or b(31) = '0' then |
a_select(2) <= '1'; |
--a_temp := a; |
b_select(2) <= '1'; |
--b_temp(31 downto 0) := b; |
else |
a_select(3) <= '1'; |
--a_temp := a_neg; |
b_select(3) <= '1'; |
--b_temp(31 downto 0) := b_neg; |
end if; |
--b_temp(63 downto 32) := ZERO; |
end if; |
elsif do_write = '1' then |
if do_hi = '0' then |
b_select(4) <= '1'; |
--b_temp(31 downto 0) := a; |
else |
b_select(5) <= '1'; |
--b_temp(63 downto 32) := a; |
end if; |
end if; |
|
if do_mult_reg = '0' then --division |
aa_select(0) <= '1'; |
--aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a; |
bb_select(0) <= '1'; |
--bb <= reg_b(33 downto 0); |
else --multiplication two-bits at a time |
case reg_b(1 downto 0) is |
when "00" => |
aa_select(1) <= '1'; |
--aa <= "00" & ZERO; |
when "01" => |
aa_select(2) <= '1'; |
--aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a; |
when "10" => |
aa_select(3) <= '1'; |
--aa <= (reg_a(31) and sign_extend) & reg_a & '0'; |
when others => |
--aa_select(4) <= '1'; |
--aa <= reg_a_times3; |
end case; |
bb_select(1) <= '1'; |
--bb <= (reg_b(63) and sign_extend) & (reg_b(63) and sign_extend) & reg_b(63 downto 32); |
end if; |
|
if count_reg(5) = '0' and start = '0' then |
count_temp := bv_inc6(count_reg); |
if do_mult_reg = '0' then --division |
--answer_temp(31 downto 1) := answer_reg(30 downto 0); |
if reg_b(63 downto 32) = ZERO and sum(32) = '0' then |
a_select(4) <= '1'; |
--a_temp := sum(31 downto 0); --aa=aa-bb; |
answer_select(1) <= '1'; |
--answer_temp(0) := '1'; |
else |
answer_select(2) <= '1'; |
--answer_temp(0) := '0'; |
end if; |
if count_reg /= "011111" then |
--b_temp(62 downto 0) := reg_b(63 downto 1); |
b_select(6) <= '1'; |
else --done with divide |
--b_temp(63 downto 32) := a_temp; |
if do_signed_reg = '0' then |
b_select(7) <= '1'; |
--b_temp(31 downto 0) := answer_temp; |
else |
b_select(8) <= '1'; |
--b_temp(31 downto 0) := bv_negate(answer_temp); |
end if; |
end if; |
else -- mult_mode |
b_select(9) <= '1'; |
--b_temp(63 downto 30) := sum; |
--b_temp(29 downto 0) := reg_b(31 downto 2); |
if count_reg = "001000" and sign_extend = '0' and --early stop |
reg_b(15 downto 0) = ZERO(15 downto 0) then |
count_temp := "111111"; |
b_select(10) <= '1'; |
--b_temp(31 downto 0) := reg_b(47 downto 16); |
end if; |
if count_reg = "000100" and sign_extend = '0' and --early stop |
reg_b(23 downto 0) = ZERO(23 downto 0) then |
count_temp := "111111"; |
b_select(11) <= '1'; |
--b_temp(31 downto 0) := reg_b(55 downto 24); |
end if; |
count_temp(5) := count_temp(4); |
end if; |
end if; |
|
if rising_edge(clk) then |
do_mult_reg <= do_mult_temp; |
do_signed_reg <= do_signed_temp; |
count_reg <= count_temp; |
reg_a <= a_temp_sig; |
reg_b <= b_temp_sig; |
answer_reg <= answer_temp_sig; |
if start = '1' then |
reg_a_times3 <= ((a_temp_sig(31) and do_signed_temp) & a_temp_sig & '0') + |
((a_temp_sig(31) and do_signed_temp) & (a_temp_sig(31) and do_signed_temp) & a_temp_sig); |
end if; |
end if; |
|
if count_reg(5) = '0' and mult_func/= mult_nothing and start = '0' then |
pause_out <= '1'; |
else |
pause_out <= '0'; |
end if; |
|
end process; |
|
|
-- Arguments |
a_msb <= reg_a(31) and sign_extend_sig; |
aa <= a_msb & a_msb & reg_a when aa_select(0)='1' else |
"00" & ZERO when aa_select(1)='1' else |
a_msb & a_msb & reg_a when aa_select(2)='1' else |
a_msb & reg_a & '0' when aa_select(3)='1' else |
reg_a_times3; |
|
b_msb <= reg_b(63) and sign_extend_sig; |
bb <= reg_b(33 downto 0) when bb_select(0)='1' else (others => 'Z'); |
bb <= b_msb & b_msb & reg_b(63 downto 32) when bb_select(1)='1' else (others => 'Z'); |
|
-- Divide: Init |
a_temp_sig <= a when a_select(0)='1' else (others => 'Z'); |
a_temp_sig <= a_neg_sig when a_select(1)='1' else (others => 'Z'); |
b_temp_sig <= '0' & b & ZERO(30 downto 0) when b_select(0)='1' else (others => 'Z'); |
b_temp_sig <= '0' & b_neg_sig & ZERO(30 downto 0) when b_select(1)='1' else (others => 'Z'); |
|
-- Multiply: Init |
a_temp_sig <= a when a_select(2)='1' else (others => 'Z'); |
b_temp_sig <= ZERO & b when b_select(2)='1' else (others => 'Z'); |
a_temp_sig <= a_neg_sig when a_select(3)='1' else (others => 'Z'); |
b_temp_sig <= ZERO & b_neg_sig when b_select(3)='1' else (others => 'Z'); |
|
-- Intermediate results |
b_temp_sig <= reg_b(63 downto 32) & a when b_select(4)='1' else (others => 'Z'); |
b_temp_sig <= a & reg_b(31 downto 0) when b_select(5)='1' else (others => 'Z'); |
|
-- Divide: Operation |
a_temp_sig <= sum(31 downto 0) when a_select(4)='1' else (others => 'Z'); |
b_temp_sig <= reg_b(63) & reg_b(63 downto 1) when b_select(6)='1' else (others => 'Z'); |
b_temp_sig <= a_temp_sig & answer_temp_sig when b_select(7)='1' else (others => 'Z'); |
b_temp_sig <= a_temp_sig & bv_negate(answer_temp_sig) when b_select(8)='1' else (others => 'Z'); |
|
-- Multiply: Operation |
b_temp_sig <= sum & reg_b(31 downto 2) when b_select(9)='1' and b_select(10)='0' and b_select(11)='0' else (others => 'Z'); |
b_temp_sig <= sum(33 downto 2) & reg_b(47 downto 16) when b_select(10)='1' else (others => 'Z'); |
b_temp_sig <= sum(33 downto 2) & reg_b(55 downto 24) when b_select(11)='1' else (others => 'Z'); |
|
-- Default values |
a_temp_sig <= reg_a when conv_integer(unsigned(a_select))=0 else (others => 'Z'); |
b_temp_sig <= reg_b when conv_integer(unsigned(b_select))=0 else (others => 'Z'); |
|
-- Result |
answer_temp_sig <= ZERO when answer_select(0)='1' else |
answer_reg(30 downto 0) & '1' when answer_select(1)='1' else |
answer_reg(30 downto 0) & '0' when answer_select(2)='1' else |
answer_reg; |
|
end generate; |
|
end; --architecture logic |
|
/vhdl/shifter.vhd
0,0 → 1,75
--------------------------------------------------------------------- |
-- TITLE: Shifter Unit |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- Matthias Gruenewald |
-- DATE CREATED: 2/2/01 |
-- FILENAME: shifter.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the 32-bit shifter unit. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity shifter is |
generic(shifter_type : string := "GENERIC"); |
port(value : in std_logic_vector(31 downto 0); |
shift_amount : in std_logic_vector(4 downto 0); |
shift_func : in shift_function_type; |
c_shift : out std_logic_vector(31 downto 0)); |
end; --entity shifter |
|
architecture logic of shifter is |
-- type shift_function_type is ( |
-- shift_nothing, shift_left_unsigned, |
-- shift_right_signed, shift_right_unsigned); |
|
signal shift1L, shift2L, shift4L, shift8L, shift16L : std_logic_vector(31 downto 0); |
signal shift1R, shift2R, shift4R, shift8R, shift16R : std_logic_vector(31 downto 0); |
signal fills : std_logic_vector(31 downto 16); |
|
begin |
fills <= "1111111111111111" when shift_func = shift_right_signed and value(31) = '1' else |
"0000000000000000"; |
shift1L <= value(30 downto 0) & '0' when shift_amount(0) = '1' else value; |
shift2L <= shift1L(29 downto 0) & "00" when shift_amount(1) = '1' else shift1L; |
shift4L <= shift2L(27 downto 0) & "0000" when shift_amount(2) = '1' else shift2L; |
shift8L <= shift4L(23 downto 0) & "00000000" when shift_amount(3) = '1' else shift4L; |
shift16L <= shift8L(15 downto 0) & ZERO(15 downto 0) when shift_amount(4) = '1' else shift8L; |
|
shift1R <= fills(31) & value(31 downto 1) when shift_amount(0) = '1' else value; |
shift2R <= fills(31 downto 30) & shift1R(31 downto 2) when shift_amount(1) = '1' else shift1R; |
shift4R <= fills(31 downto 28) & shift2R(31 downto 4) when shift_amount(2) = '1' else shift2R; |
shift8R <= fills(31 downto 24) & shift4R(31 downto 8) when shift_amount(3) = '1' else shift4R; |
shift16R <= fills(31 downto 16) & shift8R(31 downto 16) when shift_amount(4) = '1' else shift8R; |
|
-- synthesis translate_off |
GENERIC_SHIFTER: if shifter_type = "GENERIC" generate |
-- synthesis translate_on |
|
c_shift <= shift16L when shift_func = shift_left_unsigned else |
shift16R when shift_func = shift_right_unsigned or shift_func = shift_right_signed else |
ZERO; |
|
-- synthesis translate_off |
end generate; |
-- synthesis translate_on |
|
-- synopsys synthesis_off |
|
AREA_OPTIMIZED_SHIFTER: if shifter_type = "AREA_OPTIMIZED" generate |
|
c_shift <= shift16L when shift_func = shift_left_unsigned else (others => 'Z'); |
c_shift <= shift16R when shift_func = shift_right_unsigned or |
shift_func = shift_right_signed else (others => 'Z'); |
c_shift <= ZERO when shift_func = shift_nothing else (others => 'Z'); |
|
end generate; |
|
-- synopsys synthesis_on |
|
end; --architecture logic |
|
/vhdl/mem_ctrl.vhd
0,0 → 1,271
--------------------------------------------------------------------- |
-- TITLE: Memory Controller |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 1/31/01 |
-- FILENAME: mem_ctrl.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Memory controller for the Plasma CPU. |
-- Supports Big or Little Endian mode. |
-- Four cycles for a write unless a(31)='1' then two cycles. |
-- This entity could implement interfaces to: |
-- Data cache |
-- Address cache |
-- Memory management unit (MMU) |
-- DRAM controller |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity mem_ctrl is |
generic(ACCURATE_TIMING : boolean := false); |
port(clk : in std_logic; |
reset_in : in std_logic; |
pause_in : in std_logic; |
nullify_op : in std_logic; |
address_pc : in std_logic_vector(31 downto 0); |
opcode_out : out std_logic_vector(31 downto 0); |
|
address_data : in std_logic_vector(31 downto 0); |
mem_source : in mem_source_type; |
data_write : in std_logic_vector(31 downto 0); |
data_read : out std_logic_vector(31 downto 0); |
pause_out : out std_logic; |
|
mem_address : out std_logic_vector(31 downto 0); |
mem_data_w : out std_logic_vector(31 downto 0); |
mem_data_r : in std_logic_vector(31 downto 0); |
mem_byte_sel : out std_logic_vector(3 downto 0); |
mem_write : out std_logic); |
end; --entity mem_ctrl |
|
architecture logic of mem_ctrl is |
--"00" = big_endian; "11" = little_endian |
constant little_endian : std_logic_vector(1 downto 0) := "00"; |
signal opcode_reg : std_logic_vector(31 downto 0); |
signal next_opcode_reg : std_logic_vector(31 downto 0); |
|
subtype mem_state_type is std_logic_vector(1 downto 0); |
signal mem_state_reg : mem_state_type; |
constant STATE_FETCH : mem_state_type := "00"; |
constant STATE_ADDR : mem_state_type := "01"; |
constant STATE_WRITE : mem_state_type := "10"; |
constant STATE_PAUSE : mem_state_type := "11"; |
|
--ACCURATE_TIMING notes: |
--The VHDL compiler's timing calculation isn't able to realize that |
--memory reads take two clock cycles. It notices that reg_bank:reg_dest |
--is dependent on mem_ctrl:mem_data_r which is dependent on |
--mem_ctrl:mem_address which is dependent on alu:c_alu. However, |
--this dependency is only true for memory read or write cycles |
--which are multiple clock cycles. Enabling ACCURATE_TIMING |
--creates an additional 32-bit register that does nothing other |
--than letting the VHDL compiler accurately predict the maximum |
--clock speed. |
signal address_reg : std_logic_vector(31 downto 0); |
signal write_reg : std_logic; |
signal byte_sel_reg : std_logic_vector(3 downto 0); |
signal mem_state_next_sig : mem_state_type; |
signal opcode_next_sig : std_logic_vector(31 downto 0); |
signal write_next_sig : std_logic; |
signal byte_sel_next_sig : std_logic_vector(3 downto 0); |
|
begin |
|
GEN_REGS: process(clk, reset_in) |
begin |
if reset_in = '1' then |
mem_state_reg <= STATE_FETCH; |
opcode_reg <= ZERO; |
next_opcode_reg <= ZERO; |
elsif rising_edge(clk) then |
mem_state_reg <= mem_state_next_sig; |
opcode_reg <= opcode_next_sig; |
if mem_state_reg = STATE_FETCH then |
next_opcode_reg <= mem_data_r; |
end if; |
end if; |
end process; |
|
GEN_REGS2: process(clk, address_data, write_next_sig, byte_sel_next_sig) |
begin |
if rising_edge(clk) then |
if ACCURATE_TIMING then |
address_reg <= address_data; |
write_reg <= write_next_sig; |
byte_sel_reg <= byte_sel_next_sig; |
end if; |
end if; |
if not ACCURATE_TIMING then |
address_reg <= address_data; |
write_reg <= write_next_sig; |
byte_sel_reg <= byte_sel_next_sig; |
end if; |
end process; |
|
mem_proc: process(clk, reset_in, pause_in, nullify_op, |
address_pc, address_data, mem_source, data_write, |
mem_data_r, |
opcode_reg, next_opcode_reg, mem_state_reg, |
address_reg, write_reg, byte_sel_reg) |
variable data : std_logic_vector(31 downto 0); |
variable opcode_next : std_logic_vector(31 downto 0); |
variable byte_sel_next : std_logic_vector(3 downto 0); |
variable byte_sel : std_logic_vector(3 downto 0); |
variable write_next : std_logic; |
variable write_line : std_logic; |
variable mem_state_next : mem_state_type; |
variable pause : std_logic; |
variable address : std_logic_vector(31 downto 0); |
variable bits : std_logic_vector(1 downto 0); |
variable mem_data_w_v : std_logic_vector(31 downto 0); |
begin |
byte_sel_next := "0000"; |
write_next := '0'; |
pause := '0'; |
mem_state_next := mem_state_reg; |
|
data := ZERO; |
mem_data_w_v := ZERO; |
|
case mem_source is |
when mem_read32 => |
data := mem_data_r; |
when mem_read16 | mem_read16s => |
if address_reg(1) = little_endian(1) then |
data(15 downto 0) := mem_data_r(31 downto 16); |
else |
data(15 downto 0) := mem_data_r(15 downto 0); |
end if; |
if mem_source = mem_read16 or data(15) = '0' then |
data(31 downto 16) := ZERO(31 downto 16); |
else |
data(31 downto 16) := ONES(31 downto 16); |
end if; |
when mem_read8 | mem_read8s => |
bits := address_reg(1 downto 0) xor little_endian; |
case bits is |
when "00" => data(7 downto 0) := mem_data_r(31 downto 24); |
when "01" => data(7 downto 0) := mem_data_r(23 downto 16); |
when "10" => data(7 downto 0) := mem_data_r(15 downto 8); |
when others => data(7 downto 0) := mem_data_r(7 downto 0); |
end case; |
if mem_source = mem_read8 or data(7) = '0' then |
data(31 downto 8) := ZERO(31 downto 8); |
else |
data(31 downto 8) := ONES(31 downto 8); |
end if; |
when mem_write32 => |
write_next := '1'; |
mem_data_w_v := data_write; |
byte_sel_next := "1111"; |
when mem_write16 => |
write_next := '1'; |
mem_data_w_v := data_write(15 downto 0) & data_write(15 downto 0); |
if address_data(1) = little_endian(1) then |
byte_sel_next := "1100"; |
else |
byte_sel_next := "0011"; |
end if; |
when mem_write8 => |
write_next := '1'; |
mem_data_w_v := data_write(7 downto 0) & data_write(7 downto 0) & |
data_write(7 downto 0) & data_write(7 downto 0); |
bits := address_data(1 downto 0) xor little_endian; |
case bits is |
when "00" => |
byte_sel_next := "1000"; |
when "01" => |
byte_sel_next := "0100"; |
when "10" => |
byte_sel_next := "0010"; |
when others => |
byte_sel_next := "0001"; |
end case; |
when others => |
end case; |
byte_sel_next_sig <= byte_sel_next; |
write_next_sig <= write_next; |
|
opcode_next := opcode_reg; |
case mem_state_reg is --State Machine |
when STATE_FETCH => |
address := address_pc; |
write_line := '0'; |
byte_sel := "0000"; |
if mem_source = mem_fetch then --opcode fetch |
mem_state_next := STATE_FETCH; |
if pause_in = '0' then |
opcode_next := mem_data_r; |
end if; |
else --memory read or write |
pause := '1'; |
if pause_in = '0' then |
mem_state_next := STATE_ADDR; |
end if; |
end if; |
when STATE_ADDR => --address lines pre-hold |
address := address_reg; |
write_line := write_reg; |
if write_reg = '1' and address_reg(31) = '1' then |
pause := '1'; |
byte_sel := "0000"; |
if pause_in = '0' then |
mem_state_next := STATE_WRITE; --4 cycle access |
end if; |
else |
byte_sel := byte_sel_reg; |
if pause_in = '0' then |
opcode_next := next_opcode_reg; |
mem_state_next := STATE_FETCH; --2 cycle access |
end if; |
end if; |
when STATE_WRITE => |
pause := '1'; |
address := address_reg; |
write_line := write_reg; |
byte_sel := byte_sel_reg; |
if pause_in = '0' then |
mem_state_next := STATE_PAUSE; |
end if; |
when OTHERS => --STATE_PAUSE address lines post-hold |
address := address_reg; |
write_line := write_reg; |
byte_sel := "0000"; |
if pause_in = '0' then |
opcode_next := next_opcode_reg; |
mem_state_next := STATE_FETCH; |
end if; |
end case; |
|
if nullify_op = '1' and pause_in = '0' then |
opcode_next := ZERO; --NOP after beql |
end if; |
|
mem_state_next_sig <= mem_state_next; |
opcode_next_sig <= opcode_next; |
|
if reset_in = '1' then |
write_line := '0'; |
end if; |
|
opcode_out <= opcode_reg; |
data_read <= data; |
pause_out <= pause; |
mem_byte_sel <= byte_sel; |
mem_address <= address; |
mem_write <= write_line; |
|
if write_line = '1' then |
mem_data_w <= mem_data_w_v; |
else |
mem_data_w <= HIGH_Z; --ZERO; |
end if; |
|
end process; --data_proc |
|
end; --architecture logic |
|
/vhdl/control.vhd
0,0 → 1,455
--------------------------------------------------------------------- |
-- TITLE: Controller / Opcode Decoder |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/8/01 |
-- FILENAME: control.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- NOTE: MIPS(tm) is a registered trademark of MIPS Technologies. |
-- MIPS Technologies does not endorse and is not associated with |
-- this project. |
-- DESCRIPTION: |
-- Controls the CPU by decoding the opcode and generating control |
-- signals to the rest of the CPU. |
-- This entity decodes the MIPS(tm) opcode into a |
-- Very-Long-Word-Instruction. |
-- The 32-bit opcode is converted to a |
-- 6+6+6+16+5+2+3+3+2+2+3+2+4 = 60 bit VLWI opcode. |
-- Based on information found in: |
-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich |
-- and "The Designer's Guide to VHDL" by Peter J. Ashenden |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity control is |
port(opcode : in std_logic_vector(31 downto 0); |
intr_signal : in std_logic; |
rs_index : out std_logic_vector(5 downto 0); |
rt_index : out std_logic_vector(5 downto 0); |
rd_index : out std_logic_vector(5 downto 0); |
imm_out : out std_logic_vector(15 downto 0); |
alu_func : out alu_function_type; |
shift_func : out shift_function_type; |
mult_func : out mult_function_type; |
branch_func : out branch_function_type; |
a_source_out : out a_source_type; |
b_source_out : out b_source_type; |
c_source_out : out c_source_type; |
pc_source_out: out pc_source_type; |
mem_source_out:out mem_source_type); |
end; --entity control |
|
architecture logic of control is |
-- type alu_function_type is (alu_nothing, alu_add, alu_subtract, |
-- alu_less_than, alu_less_than_signed, |
-- alu_or, alu_and, alu_xor, alu_nor); |
-- type shift_function_type is ( |
-- shift_nothing, shift_left_unsigned, |
-- shift_right_signed, shift_right_unsigned); |
-- type mult_function_type is ( |
-- mult_nothing, mult_read_lo, mult_read_hi, mult_write_lo, |
-- mult_write_hi, mult_mult, mult_divide, mult_signed_divide); |
-- type a_source_type is (from_reg_source, from_imm10_6); |
-- type b_source_type is (from_reg_target, from_imm, from_signed_imm); |
-- type c_source_type is (from_null, from_alu, from_shift, |
-- from_mult, from_memory, from_pc, from_imm_shift16, |
-- from_reg_source_nez, from_reg_source_eqz); |
-- type pc_source_type is (from_inc4, from_inc8, from_reg_source, |
-- from_opcode25_0, from_branch, from_lbranch); |
begin |
|
control_proc: process(opcode, intr_signal) |
variable op, func : std_logic_vector(5 downto 0); |
variable rs, rt, rd : std_logic_vector(5 downto 0); |
variable rtx : std_logic_vector(4 downto 0); |
variable imm : std_logic_vector(15 downto 0); |
variable alu_function : alu_function_type; |
variable shift_function : shift_function_type; |
variable mult_function : mult_function_type; |
variable a_source : a_source_type; |
variable b_source : b_source_type; |
variable c_source : c_source_type; |
variable pc_source : pc_source_type; |
variable branch_function: branch_function_type; |
variable mem_source : mem_source_type; |
begin |
alu_function := alu_nothing; |
shift_function := shift_nothing; |
mult_function := mult_nothing; |
a_source := a_from_reg_source; |
b_source := b_from_reg_target; |
c_source := c_from_null; |
pc_source := from_inc4; |
branch_function := branch_eq; |
mem_source := mem_fetch; |
op := opcode(31 downto 26); |
rs := '0' & opcode(25 downto 21); |
rt := '0' & opcode(20 downto 16); |
rtx := opcode(20 downto 16); |
rd := '0' & opcode(15 downto 11); |
func := opcode(5 downto 0); |
imm := opcode(15 downto 0); |
|
case op is |
when "000000" => --SPECIAL |
case func is |
when "000000" => --SLL r[rd]=r[rt]<<re; |
a_source := a_from_imm10_6; |
c_source := c_from_shift; |
shift_function := shift_left_unsigned; |
when "000010" => --SRL r[rd]=u[rt]>>re; |
a_source := a_from_imm10_6; |
c_source := c_from_shift; |
shift_function := shift_right_unsigned; |
when "000011" => --SRA r[rd]=r[rt]>>re; |
a_source := a_from_imm10_6; |
c_source := c_from_shift; |
shift_function := shift_right_signed; |
when "000100" => --SLLV r[rd]=r[rt]<<r[rs]; |
c_source := c_from_shift; |
shift_function := shift_left_unsigned; |
when "000110" => --SRLV r[rd]=u[rt]>>r[rs]; |
c_source := c_from_shift; |
shift_function := shift_right_unsigned; |
when "000111" => --SRAV r[rd]=r[rt]>>r[rs]; |
c_source := c_from_shift; |
shift_function := shift_right_signed; |
when "001000" => --JR s->pc_next=r[rs]; |
pc_source := from_branch; |
alu_function := alu_add; |
branch_function := branch_yes; |
when "001001" => --JALR r[rd]=s->pc_next; s->pc_next=r[rs]; |
c_source := c_from_pc_plus4; |
pc_source := from_branch; |
alu_function := alu_add; |
branch_function := branch_yes; |
when "001010" => --MOVZ if(!r[rt]) r[rd]=r[rs]; /*IV*/ |
-- c_source := c_from_reg_source_eqz; |
when "001011" => --MOVN if(r[rt]) r[rd]=r[rs]; /*IV*/ |
-- c_source := from_reg_source_nez; |
when "001100" => --SYSCALL |
-- if(r[4]==0) printf("0x%8.8lx ",r[5]); |
when "001101" => --BREAK s->wakeup=1; |
when "001111" => --SYNC s->wakeup=1; |
when "010000" => --MFHI r[rd]=s->hi; |
c_source := c_from_mult; |
mult_function := mult_read_hi; |
when "010001" => --FTHI s->hi=r[rs]; |
mult_function := mult_write_hi; |
when "010010" => --MFLO r[rd]=s->lo; |
c_source := c_from_mult; |
mult_function := mult_read_lo; |
when "010011" => --MTLO s->lo=r[rs]; |
mult_function := mult_write_lo; |
when "011000" => --MULT s->lo=r[rs]*r[rt]; s->hi=0; |
mult_function := mult_signed_mult; |
when "011001" => --MULTU s->lo=r[rs]*r[rt]; s->hi=0; |
mult_function := mult_mult; |
when "011010" => --DIV s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; |
mult_function := mult_signed_divide; |
when "011011" => --DIVU s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; |
mult_function := mult_divide; |
when "100000" => --ADD r[rd]=r[rs]+r[rt]; |
c_source := c_from_alu; |
alu_function := alu_add; |
when "100001" => --ADDU r[rd]=r[rs]+r[rt]; |
c_source := c_from_alu; |
alu_function := alu_add; |
when "100010" => --SUB r[rd]=r[rs]-r[rt]; |
c_source := c_from_alu; |
alu_function := alu_subtract; |
when "100011" => --SUBU r[rd]=r[rs]-r[rt]; |
c_source := c_from_alu; |
alu_function := alu_subtract; |
when "100100" => --AND r[rd]=r[rs]&r[rt]; |
c_source := c_from_alu; |
alu_function := alu_and; |
when "100101" => --OR r[rd]=r[rs]|r[rt]; |
c_source := c_from_alu; |
alu_function := alu_or; |
when "100110" => --XOR r[rd]=r[rs]^r[rt]; |
c_source := c_from_alu; |
alu_function := alu_xor; |
when "100111" => --NOR r[rd]=~(r[rs]|r[rt]); |
c_source := c_from_alu; |
alu_function := alu_nor; |
when "101010" => --SLT r[rd]=r[rs]<r[rt]; |
c_source := c_from_alu; |
alu_function := alu_less_than_signed; |
when "101011" => --SLTU r[rd]=u[rs]<u[rt]; |
c_source := c_from_alu; |
alu_function := alu_less_than; |
when "101101" => --DADDU r[rd]=r[rs]+u[rt]; |
c_source := c_from_alu; |
alu_function := alu_add; |
when "110001" => --TGEU |
when "110010" => --TLT |
when "110011" => --TLTU |
when "110100" => --TEQ |
when "110110" => --TNE |
when others => |
end case; |
when "000001" => --REGIMM |
rt := "000000"; |
rd := "011111"; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_branch; |
branch_function := branch_gtz; |
--if(test) pc=pc+imm*4 |
case rtx is |
when "10000" => --BLTZAL r[31]=s->pc_next; branch=r[rs]<0; |
c_source := c_from_pc_plus4; |
branch_function := branch_ltz; |
when "00000" => --BLTZ branch=r[rs]<0; |
branch_function := branch_ltz; |
when "10001" => --BGEZAL r[31]=s->pc_next; branch=r[rs]>=0; |
c_source := c_from_pc_plus4; |
branch_function := branch_gez; |
when "00001" => --BGEZ branch=r[rs]>=0; |
branch_function := branch_gez; |
when "10010" => --BLTZALL r[31]=s->pc_next; lbranch=r[rs]<0; |
c_source := c_from_pc_plus4; |
pc_source := from_lbranch; |
branch_function := branch_ltz; |
when "00010" => --BLTZL lbranch=r[rs]<0; |
pc_source := from_lbranch; |
branch_function := branch_ltz; |
when "10011" => --BGEZALL r[31]=s->pc_next; lbranch=r[rs]>=0; |
c_source := c_from_pc_plus4; |
pc_source := from_lbranch; |
branch_function := branch_gez; |
when "00011" => --BGEZL lbranch=r[rs]>=0; |
pc_source := from_lbranch; |
branch_function := branch_gez; |
when others => |
end case; |
when "000011" => --JAL r[31]=s->pc_next; s->pc_next=(s->pc&0xf0000000)|target; |
c_source := c_from_pc_plus4; |
rd := "011111"; |
pc_source := from_opcode25_0; |
when "000010" => --J s->pc_next=(s->pc&0xf0000000)|target; |
pc_source := from_opcode25_0; |
when "000100" => --BEQ branch=r[rs]==r[rt]; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_branch; |
branch_function := branch_eq; |
when "000101" => --BNE branch=r[rs]!=r[rt]; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_branch; |
branch_function := branch_ne; |
when "000110" => --BLEZ branch=r[rs]<=0; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_branch; |
branch_function := branch_lez; |
when "000111" => --BGTZ branch=r[rs]>0; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_branch; |
branch_function := branch_gtz; |
when "001000" => --ADDI r[rt]=r[rs]+(short)imm; |
b_source := b_from_signed_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_add; |
when "001001" => --ADDIU u[rt]=u[rs]+(short)imm; |
b_source := b_from_signed_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_add; |
when "001010" => --SLTI r[rt]=r[rs]<(short)imm; |
b_source := b_from_signed_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_less_than_signed; |
when "001011" => --SLTIU u[rt]=u[rs]<(unsigned long)(short)imm; |
b_source := b_from_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_less_than; |
when "001100" => --ANDI r[rt]=r[rs]&imm; |
b_source := b_from_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_and; |
when "001101" => --ORI r[rt]=r[rs]|imm; |
b_source := b_from_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_or; |
when "001110" => --XORI r[rt]=r[rs]^imm; |
b_source := b_from_imm; |
c_source := c_from_alu; |
rd := rt; |
alu_function := alu_xor; |
when "001111" => --LUI r[rt]=(imm<<16); |
c_source := c_from_imm_shift16; |
rd := rt; |
when "010000" => --COP0 |
alu_function := alu_or; |
c_source := c_from_alu; |
if opcode(23) = '0' then --move from CP0 |
rs := '1' & opcode(15 downto 11); |
rt := "000000"; |
rd := '0' & opcode(20 downto 16); |
else --move to CP0 |
rs := "000000"; |
rd(5) := '1'; |
end if; |
when "010001" => --COP1 |
when "010010" => --COP2 |
when "010011" => --COP3 |
when "010100" => --BEQL lbranch=r[rs]==r[rt]; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_lbranch; |
branch_function := branch_eq; |
when "010101" => --BNEL lbranch=r[rs]!=r[rt]; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_lbranch; |
branch_function := branch_ne; |
when "010110" => --BLEZL lbranch=r[rs]<=0; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_lbranch; |
branch_function := branch_lez; |
when "010111" => --BGTZL lbranch=r[rs]>0; |
a_source := a_from_pc; |
b_source := b_from_immX4; |
alu_function := alu_add; |
pc_source := from_lbranch; |
branch_function := branch_gtz; |
when "100000" => --LB r[rt]=*(signed char*)ptr; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read8s; --address=(short)imm+r[rs]; |
when "100001" => --LH r[rt]=*(signed short*)ptr; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read16s; --address=(short)imm+r[rs]; |
when "100010" => --LWL //Not Implemented |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read32; |
when "100011" => --LW r[rt]=*(long*)ptr; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read32; |
when "100100" => --LBU r[rt]=*(unsigned char*)ptr; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read8; --address=(short)imm+r[rs]; |
when "100101" => --LHU r[rt]=*(unsigned short*)ptr; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
rd := rt; |
c_source := c_from_memory; |
mem_source := mem_read16; --address=(short)imm+r[rs]; |
when "100110" => --LWR //Not Implemented |
when "101000" => --SB *(char*)ptr=(char)r[rt]; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
mem_source := mem_write8; --address=(short)imm+r[rs]; |
when "101001" => --SH *(short*)ptr=(short)r[rt]; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
mem_source := mem_write16; |
when "101010" => --SWL //Not Implemented |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
mem_source := mem_write32; --address=(short)imm+r[rs]; |
when "101011" => --SW *(long*)ptr=r[rt]; |
a_source := a_from_reg_source; |
b_source := b_from_signed_imm; |
alu_function := alu_add; |
mem_source := mem_write32; --address=(short)imm+r[rs]; |
when "101110" => --SWR //Not Implemented |
when "101111" => --CACHE |
when "110000" => --LL r[rt]=*(long*)ptr; |
when "110001" => --LWC1 |
when "110010" => --LWC2 |
when "110011" => --LWC3 |
when "110101" => --LDC1 |
when "110110" => --LDC2 |
when "110111" => --LDC3 |
when "111000" => --SC *(long*)ptr=r[rt]; r[rt]=1; |
when "111001" => --SWC1 |
when "111010" => --SWC2 |
when "111011" => --SWC3 |
when "111101" => --SDC1 |
when "111110" => --SDC2 |
when "111111" => --SDC3 |
when others => |
end case; |
|
if c_source = c_from_null then |
rd := "000000"; |
end if; |
|
if intr_signal = '1' then |
rs := "111111"; --interrupt vector |
rt := "000000"; |
rd := "101110"; --save PC in EPC |
alu_function := alu_or; |
shift_function := shift_nothing; |
mult_function := mult_nothing; |
branch_function := branch_yes; |
a_source := a_from_reg_source; |
b_source := b_from_reg_target; |
c_source := c_from_pc; |
pc_source := from_lbranch; |
mem_source := mem_fetch; |
end if; |
|
rs_index <= rs; |
rt_index <= rt; |
rd_index <= rd; |
imm_out <= imm; |
alu_func <= alu_function; |
shift_func <= shift_function; |
mult_func <= mult_function; |
branch_func <= branch_function; |
a_source_out <= a_source; |
b_source_out <= b_source; |
c_source_out <= c_source; |
pc_source_out <= pc_source; |
mem_source_out <= mem_source; |
|
end process; |
|
end; --logic |
|
/vhdl/alu.vhd
0,0 → 1,94
--------------------------------------------------------------------- |
-- TITLE: Arithmetic Logic Unit |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/8/01 |
-- FILENAME: alu.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the ALU. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity alu is |
generic(adder_type : string := "GENERIC"; |
alu_type : string := "GENERIC"); |
port(a_in : in std_logic_vector(31 downto 0); |
b_in : in std_logic_vector(31 downto 0); |
alu_function : in alu_function_type; |
c_alu : out std_logic_vector(31 downto 0)); |
end; --alu |
|
architecture logic of alu is |
-- type alu_function_type is (alu_nothing, alu_add, alu_subtract, |
-- alu_less_than, alu_less_than_signed, |
-- alu_or, alu_and, alu_xor, alu_nor); |
|
signal aa, bb, sum : std_logic_vector(32 downto 0); |
signal do_add : std_logic; |
signal sign_ext : std_logic; |
begin |
|
do_add <= '1' when alu_function = alu_add else '0'; |
sign_ext <= '0' when alu_function = alu_less_than else '1'; |
aa <= (a_in(31) and sign_ext) & a_in; |
bb <= (b_in(31) and sign_ext) & b_in; |
|
-- synthesis translate_off |
GENERIC_ALU: if alu_type="GENERIC" generate |
-- synthesis translate_on |
|
c_alu <= sum(31 downto 0) when alu_function=alu_add or alu_function=alu_subtract else |
ZERO(31 downto 1) & sum(32) when alu_function=alu_less_than or alu_function=alu_less_than_signed else |
a_in or b_in when alu_function=alu_or else |
a_in and b_in when alu_function=alu_and else |
a_in xor b_in when alu_function=alu_xor else |
a_in nor b_in when alu_function=alu_nor else |
ZERO; |
|
-- synthesis translate_off |
end generate; |
-- synthesis translate_on |
|
-- synopsys synthesis_off |
|
AREA_OPTIMIZED_ALU: if alu_type="AREA_OPTIMIZED" generate |
|
c_alu <= sum(31 downto 0) when alu_function=alu_add or alu_function=alu_subtract else (others => 'Z'); |
c_alu <= ZERO(31 downto 1) & sum(32) when alu_function=alu_less_than or alu_function=alu_less_than_signed else (others => 'Z'); |
c_alu <= a_in or b_in when alu_function=alu_or else (others => 'Z'); |
c_alu <= a_in and b_in when alu_function=alu_and else (others => 'Z'); |
c_alu <= a_in xor b_in when alu_function=alu_xor else (others => 'Z'); |
c_alu <= a_in nor b_in when alu_function=alu_nor else (others => 'Z'); |
c_alu <= ZERO when alu_function=alu_nothing else (others => 'Z'); |
|
end generate; |
|
generic_adder: if adder_type = "GENERIC" generate |
sum <= bv_adder(aa, bb, do_add); |
end generate; --generic_adder |
|
--For Altera |
lpm_adder: if adder_type = "ALTERA" generate |
lpm_add_sub_component : lpm_add_sub |
GENERIC MAP ( |
lpm_width => 33, |
lpm_direction => "UNUSED", |
lpm_type => "LPM_ADD_SUB", |
lpm_hint => "ONE_INPUT_IS_CONSTANT=NO" |
) |
PORT MAP ( |
dataa => aa, |
add_sub => do_add, |
datab => bb, |
result => sum |
); |
end generate; --lpm_adder |
|
-- synopsys synthesis_on |
|
end; --architecture logic |
|
/vhdl/tbench.vhd
0,0 → 1,66
--------------------------------------------------------------------- |
-- TITLE: Test Bench |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 4/21/01 |
-- FILENAME: tbench.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- This entity provides a test bench for testing the Plasma CPU core. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity tbench is |
end; --entity tbench |
|
architecture logic of tbench is |
constant memory_type : string := |
"GENERIC"; |
-- "ALTERA"; |
-- "XILINX"; |
|
constant log_file : string := |
-- "UNUSED" |
"output.txt"; |
|
signal clk : std_logic := '1'; |
signal reset : std_logic := '1'; |
signal interrupt : std_logic := '0'; |
signal mem_write : std_logic; |
signal mem_address : std_logic_vector(31 downto 0); |
signal mem_data : std_logic_vector(31 downto 0); |
signal mem_pause : std_logic := '0'; |
signal mem_byte_sel: std_logic_vector(3 downto 0); |
signal uart_read : std_logic; |
signal uart_write : std_logic; |
begin --architecture |
clk <= not clk after 50 ns; |
reset <= '0' after 500 ns; |
|
--Uncomment the line below to test interrupts |
-- interrupt <= '1' after 20 us when interrupt = '0' else '0' after 400 ns; |
--Uncomment the line below to test mem_pause |
-- mem_pause <= '1' after 100 ns when mem_pause = '0' else '0' after 100 ns; |
|
u1: plasma |
generic map (memory_type => memory_type, |
log_file => log_file) |
PORT MAP ( |
clk_in => clk, |
reset_in => reset, |
intr_in => interrupt, |
|
uart_read => uart_read, |
uart_write => uart_write, |
|
mem_address_out => mem_address, |
mem_data => mem_data, |
mem_byte_sel_out => mem_byte_sel, |
mem_write_out => mem_write, |
mem_pause_in => mem_pause); |
|
end; --architecture logic |
|
/vhdl/plasma.vhd
0,0 → 1,87
--------------------------------------------------------------------- |
-- TITLE: Plasma (CPU core with memory) |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 6/4/02 |
-- FILENAME: plasma.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- This entity combines the CPU core with memory and a UART. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity plasma is |
generic(memory_type : string := "ALTERA"; |
log_file : string := "UNUSED"); |
port(clk_in : in std_logic; |
reset_in : in std_logic; |
intr_in : in std_logic; |
|
uart_read : in std_logic; |
uart_write : out std_logic; |
|
mem_address_out : out std_logic_vector(31 downto 0); |
mem_data : out std_logic_vector(31 downto 0); |
mem_byte_sel_out : out std_logic_vector(3 downto 0); |
mem_write_out : out std_logic; |
mem_pause_in : in std_logic); |
end; --entity plasma |
|
architecture logic of plasma is |
signal mem_address : std_logic_vector(31 downto 0); |
signal mem_data_r : std_logic_vector(31 downto 0); |
signal mem_data_w : std_logic_vector(31 downto 0); |
signal mem_byte_sel : std_logic_vector(3 downto 0); |
signal mem_write : std_logic; |
signal mem_pause : std_logic; |
signal mem_pause_uart : std_logic; |
signal uart_sel : std_logic; |
begin --architecture |
uart_sel <= '1' when mem_address(12 downto 0) = ONES(12 downto 0) and |
mem_byte_sel /= "0000" else '0'; |
mem_data <= mem_data_r; |
mem_pause <= (mem_pause_in and not uart_sel) or mem_pause_uart; |
|
u1_cpu: mlite_cpu |
generic map (memory_type => memory_type) |
PORT MAP ( |
clk => clk_in, |
reset_in => reset_in, |
intr_in => intr_in, |
|
mem_address => mem_address, |
mem_data_w => mem_data_w, |
mem_data_r => mem_data_r, |
mem_byte_sel => mem_byte_sel, |
mem_write => mem_write, |
mem_pause => mem_pause); |
|
u2_ram: ram |
generic map (memory_type => memory_type) |
PORT MAP ( |
clk => clk_in, |
mem_byte_sel => mem_byte_sel, |
mem_write => mem_write, |
mem_address => mem_address, |
mem_data_w => mem_data_w, |
mem_data_r => mem_data_r); |
|
u3_uart: uart |
generic map (log_file => log_file) |
port map( |
clk => clk_in, |
reset => reset_in, |
uart_sel => uart_sel, |
data => mem_data_w(7 downto 0), |
uart_write => uart_write, |
uart_read => uart_read, |
pause => mem_pause_uart); |
|
mem_address_out <= mem_address; |
mem_byte_sel_out <= mem_byte_sel; |
mem_write_out <= mem_write; |
|
end; --architecture logic |
/vhdl/makefile
0,0 → 1,119
#Makefile for Plasma |
|
#for ModelSim |
#WORK_DIR = work |
#DEP_FILE = _primary.dat |
#COMPILE = vcom -check_synthesis |
|
#for FREE VHDL simulator http://www.symphonyeda.com |
#WARNING: vhdle now deletes the output.txt if terminated by a ^C |
WORK_DIR = work.sym |
DEP_FILE = prim.dep |
COMPILE = vhdlp -s |
|
all: $(WORK_DIR)/tbench/$(DEP_FILE) |
|
run: all |
-@del output.txt |
vhdle -t 30us tbench |
type output.txt|more |
|
run2: all |
-@del output.txt |
vhdle -t 50us tbench |
type output.txt|more |
|
run3: all |
-@del output.txt |
vhdle -t 100us tbench |
type output.txt|more |
|
opcodes: all |
make -C ..\tools opcodes |
vhdle -t 200us tbench |
@type output.txt|more |
|
simulate: all |
vhdle -s -t 10us tbench -do simili.cmd -list trace.txt |
-@..\tools\tracehex.exe |
-@start ed trace2.txt |
|
simulate2: all |
vhdle -s -t 4us tbench -do simili.cmd -list trace.txt |
-@..\tools\tracehex.exe |
-@ed trace2.txt |
|
$(WORK_DIR)/lpm_pack/$(DEP_FILE): lpm_pack.vhd |
$(COMPILE) lpm_pack.vhd |
|
$(WORK_DIR)/lpm_model/$(DEP_FILE): lpm_model.vhd |
$(COMPILE) -87 lpm_model.vhd |
|
$(WORK_DIR)/mlite_pack/$(DEP_FILE): mlite_pack.vhd |
$(COMPILE) mlite_pack.vhd |
|
$(WORK_DIR)/alu/$(DEP_FILE): mlite_pack.vhd alu.vhd |
$(COMPILE) alu.vhd |
|
$(WORK_DIR)/bus_mux/$(DEP_FILE): mlite_pack.vhd bus_mux.vhd |
$(COMPILE) bus_mux.vhd |
|
$(WORK_DIR)/control/$(DEP_FILE): mlite_pack.vhd control.vhd |
$(COMPILE) control.vhd |
|
$(WORK_DIR)/mem_ctrl/$(DEP_FILE): mlite_pack.vhd mem_ctrl.vhd |
$(COMPILE) mem_ctrl.vhd |
|
$(WORK_DIR)/mult/$(DEP_FILE): mlite_pack.vhd mult.vhd |
$(COMPILE) mult.vhd |
|
$(WORK_DIR)/pc_next/$(DEP_FILE): mlite_pack.vhd pc_next.vhd |
$(COMPILE) pc_next.vhd |
|
$(WORK_DIR)/reg_bank/$(DEP_FILE): mlite_pack.vhd reg_bank.vhd |
$(COMPILE) reg_bank.vhd |
|
$(WORK_DIR)/shifter/$(DEP_FILE): mlite_pack.vhd shifter.vhd |
$(COMPILE) shifter.vhd |
|
$(WORK_DIR)/pipeline/$(DEP_FILE): mlite_pack.vhd pipeline.vhd |
$(COMPILE) pipeline.vhd |
|
$(WORK_DIR)/mlite_cpu/$(DEP_FILE): mlite_cpu.vhd \ |
$(WORK_DIR)/mlite_pack/$(DEP_FILE) \ |
$(WORK_DIR)/alu/$(DEP_FILE) \ |
$(WORK_DIR)/bus_mux/$(DEP_FILE) \ |
$(WORK_DIR)/control/$(DEP_FILE) \ |
$(WORK_DIR)/mem_ctrl/$(DEP_FILE) \ |
$(WORK_DIR)/mult/$(DEP_FILE) \ |
$(WORK_DIR)/pc_next/$(DEP_FILE) \ |
$(WORK_DIR)/reg_bank/$(DEP_FILE) \ |
$(WORK_DIR)/shifter/$(DEP_FILE) \ |
$(WORK_DIR)/pipeline/$(DEP_FILE) |
$(COMPILE) mlite_cpu.vhd |
|
$(WORK_DIR)/ram/$(DEP_FILE): mlite_pack.vhd ram.vhd |
$(COMPILE) -87 ram.vhd |
|
$(WORK_DIR)/uart/$(DEP_FILE): mlite_pack.vhd uart.vhd |
$(COMPILE) -87 uart.vhd |
|
$(WORK_DIR)/plasma/$(DEP_FILE): mlite_pack.vhd plasma.vhd \ |
$(WORK_DIR)/mlite_cpu/$(DEP_FILE) \ |
$(WORK_DIR)/ram/$(DEP_FILE) \ |
$(WORK_DIR)/uart/$(DEP_FILE) |
$(COMPILE) plasma.vhd |
|
$(WORK_DIR)/plasma_if/$(DEP_FILE): mlite_pack.vhd plasma_if.vhd \ |
$(WORK_DIR)/plasma/$(DEP_FILE) |
$(COMPILE) plasma_if.vhd |
|
$(WORK_DIR)/tbench/$(DEP_FILE): mlite_pack.vhd tbench.vhd \ |
$(WORK_DIR)/plasma/$(DEP_FILE) \ |
$(WORK_DIR)/plasma_if/$(DEP_FILE) |
$(COMPILE) tbench.vhd |
|
altera: $(WORK_DIR)/lpm_pack/$(DEP_FILE) \ |
$(WORK_DIR)/lpm_model/$(DEP_FILE) |
echo UNUSED > UNUSED |
|
/vhdl/ram.vhd
0,0 → 1,184
--------------------------------------------------------------------- |
-- TITLE: Random Access Memory |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 4/21/01 |
-- FILENAME: ram.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the RAM, reads the executable from either "code.txt", |
-- or for Altera "code[0-3].hex". |
-- Modified from "The Designer's Guide to VHDL" by Peter J. Ashenden |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_misc.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_unsigned.all; |
use ieee.std_logic_textio.all; |
use std.textio.all; |
use work.mlite_pack.all; |
|
entity ram is |
generic(memory_type : string := "GENERIC"); |
port(clk : in std_logic; |
mem_byte_sel : in std_logic_vector(3 downto 0); |
mem_write : in std_logic; |
mem_address : in std_logic_vector(31 downto 0); |
mem_data_w : in std_logic_vector(31 downto 0); |
mem_data_r : out std_logic_vector(31 downto 0)); |
end; --entity ram |
|
architecture logic of ram is |
constant ADDRESS_WIDTH : natural := 13; |
signal clk_inv : std_logic; |
signal mem_sel : std_logic; |
signal read_enable : std_logic; |
signal write_byte_enable : std_logic_vector(3 downto 0); |
begin |
clk_inv <= not clk; |
mem_sel <= '1' when mem_address(30 downto ADDRESS_WIDTH) = ZERO(30 downto ADDRESS_WIDTH) else |
'0'; |
read_enable <= mem_sel and not mem_write; |
write_byte_enable <= mem_byte_sel when mem_sel = '1' else |
"0000"; |
|
generic_ram: |
if memory_type = "GENERIC" generate |
ram_proc: process(clk, mem_byte_sel, mem_write, |
mem_address, mem_data_w, mem_sel) |
variable mem_size : natural := 2 ** ADDRESS_WIDTH; |
variable data : std_logic_vector(31 downto 0); |
subtype word is std_logic_vector(mem_data_w'length-1 downto 0); |
type storage_array is |
array(natural range 0 to mem_size/4 - 1) of word; |
variable storage : storage_array; |
variable index : natural := 0; |
file load_file : text is in "code.txt"; |
variable hex_file_line : line; |
begin |
--load in the ram executable image |
if index = 0 then |
while not endfile(load_file) loop |
--The following two lines had to be commented out for synthesis |
readline(load_file, hex_file_line); |
hread(hex_file_line, data); |
storage(index) := data; |
index := index + 1; |
end loop; |
end if; |
|
index := conv_integer(mem_address(ADDRESS_WIDTH-1 downto 2)); |
data := storage(index); |
|
if mem_sel = '1' then |
if mem_write = '0' then |
mem_data_r <= data; |
end if; |
if mem_byte_sel(0) = '1' then |
data(7 downto 0) := mem_data_w(7 downto 0); |
end if; |
if mem_byte_sel(1) = '1' then |
data(15 downto 8) := mem_data_w(15 downto 8); |
end if; |
if mem_byte_sel(2) = '1' then |
data(23 downto 16) := mem_data_w(23 downto 16); |
end if; |
if mem_byte_sel(3) = '1' then |
data(31 downto 24) := mem_data_w(31 downto 24); |
end if; |
end if; |
|
if rising_edge(clk) then |
if mem_write = '1' then |
storage(index) := data; |
end if; |
end if; |
end process; |
end generate; --generic_ram |
|
|
altera_ram: |
if memory_type = "ALTERA" generate |
--Quartus II does not allow asynchronous RAM to be initialized |
--since the RAM may see glitches on the write enable during powerup. |
--Making lpm_address_control="REGISTERED" makes the RAM synchronous |
--but then the reads are delayed by a clock cycle. |
--Inverting the RAM clock appears to solve the clock cycle delay problem. |
lpm_ram_io_component0 : lpm_ram_dq |
GENERIC MAP ( |
intended_device_family => "UNUSED", |
lpm_width => 8, |
lpm_widthad => ADDRESS_WIDTH-2, |
lpm_indata => "REGISTERED", |
lpm_address_control => "REGISTERED", |
lpm_outdata => "UNREGISTERED", |
lpm_file => "code0.hex", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DQ") |
PORT MAP ( |
data => mem_data_w(31 downto 24), |
address => mem_address(ADDRESS_WIDTH-1 downto 2), |
inclock => clk_inv, |
we => write_byte_enable(3), |
q => mem_data_r(31 downto 24)); |
|
lpm_ram_io_component1 : lpm_ram_dq |
GENERIC MAP ( |
intended_device_family => "UNUSED", |
lpm_width => 8, |
lpm_widthad => ADDRESS_WIDTH-2, |
lpm_indata => "REGISTERED", |
lpm_address_control => "REGISTERED", |
lpm_outdata => "UNREGISTERED", |
lpm_file => "code1.hex", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DQ") |
PORT MAP ( |
data => mem_data_w(23 downto 16), |
address => mem_address(ADDRESS_WIDTH-1 downto 2), |
inclock => clk_inv, |
we => write_byte_enable(2), |
q => mem_data_r(23 downto 16)); |
|
lpm_ram_io_component2 : lpm_ram_dq |
GENERIC MAP ( |
intended_device_family => "UNUSED", |
lpm_width => 8, |
lpm_widthad => ADDRESS_WIDTH-2, |
lpm_indata => "REGISTERED", |
lpm_address_control => "REGISTERED", |
lpm_outdata => "UNREGISTERED", |
lpm_file => "code2.hex", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DQ") |
PORT MAP ( |
data => mem_data_w(15 downto 8), |
address => mem_address(ADDRESS_WIDTH-1 downto 2), |
inclock => clk_inv, |
we => write_byte_enable(1), |
q => mem_data_r(15 downto 8)); |
|
lpm_ram_io_component3 : lpm_ram_dq |
GENERIC MAP ( |
intended_device_family => "UNUSED", |
lpm_width => 8, |
lpm_widthad => ADDRESS_WIDTH-2, |
lpm_indata => "REGISTERED", |
lpm_address_control => "REGISTERED", |
lpm_outdata => "UNREGISTERED", |
lpm_file => "code3.hex", |
use_eab => "ON", |
lpm_type => "LPM_RAM_DQ") |
PORT MAP ( |
data => mem_data_w(7 downto 0), |
address => mem_address(ADDRESS_WIDTH-1 downto 2), |
inclock => clk_inv, |
we => write_byte_enable(0), |
q => mem_data_r(7 downto 0)); |
|
end generate; --altera_ram |
|
end; --architecture logic |
|
/vhdl/bus_mux.vhd
0,0 → 1,138
--------------------------------------------------------------------- |
-- TITLE: Bus Multiplexer / Signal Router |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/8/01 |
-- FILENAME: bus_mux.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- This entity is the main signal router. |
-- It multiplexes signals from multiple sources to the correct location. |
-- The outputs are as follows: |
-- a_bus : goes to the ALU |
-- b_bus : goes to the ALU |
-- reg_dest_out : goes to the register bank |
-- take_branch : goes to pc_next |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity bus_mux is |
port(imm_in : in std_logic_vector(15 downto 0); |
reg_source : in std_logic_vector(31 downto 0); |
a_mux : in a_source_type; |
a_out : out std_logic_vector(31 downto 0); |
|
reg_target : in std_logic_vector(31 downto 0); |
b_mux : in b_source_type; |
b_out : out std_logic_vector(31 downto 0); |
|
c_bus : in std_logic_vector(31 downto 0); |
c_memory : in std_logic_vector(31 downto 0); |
c_pc : in std_logic_vector(31 downto 0); |
c_pc_plus4 : in std_logic_vector(31 downto 0); |
c_mux : in c_source_type; |
reg_dest_out : out std_logic_vector(31 downto 0); |
|
branch_func : in branch_function_type; |
take_branch : out std_logic); |
end; --entity bus_mux |
|
architecture logic of bus_mux is |
begin |
-- type a_source_type is (a_from_reg_source, a_from_imm10_6); |
-- type b_source_type is (b_from_reg_target, b_from_imm, b_from_signed_imm); |
-- type c_source_type is (c_from_null, c_from_alu, c_from_shift, |
-- c_from_mult, c_from_memory, c_from_pc, c_from_imm_shift16, |
-- c_from_reg_source_nez, c_from_reg_source_eqz); |
amux: process(reg_source, imm_in, a_mux, c_pc) |
begin |
case a_mux is |
when a_from_reg_source => |
a_out <= reg_source; |
when a_from_imm10_6 => |
a_out(31 downto 5) <= ZERO(31 downto 5); |
a_out(4 downto 0) <= imm_in(10 downto 6); |
when others => --a_from_pc |
a_out <= c_pc; |
end case; |
end process; |
|
bmux: process(reg_target, imm_in, b_mux) |
begin |
case b_mux is |
when b_from_reg_target => |
b_out <= reg_target; |
when b_from_imm => |
b_out <= ZERO(31 downto 16) & imm_in; |
when b_from_signed_imm => |
if imm_in(15) = '0' then |
b_out(31 downto 16) <= ZERO(31 downto 16); |
else |
b_out(31 downto 16) <= "1111111111111111"; |
end if; |
b_out(15 downto 0) <= imm_in; |
when others => --b_from_immX4 |
if imm_in(15) = '0' then |
b_out(31 downto 18) <= "00000000000000"; |
else |
b_out(31 downto 18) <= "11111111111111"; |
end if; |
b_out(17 downto 0) <= imm_in & "00"; |
end case; |
end process; |
|
cmux: process(c_bus, c_memory, c_pc, c_pc_plus4, imm_in, c_mux) |
begin |
case c_mux is |
when c_from_alu => -- | c_from_shift | c_from_mult => |
reg_dest_out <= c_bus; |
when c_from_memory => |
reg_dest_out <= c_memory; |
when c_from_pc => |
reg_dest_out <= c_pc(31 downto 3) & "000"; --backup one opcode |
when c_from_pc_plus4 => |
reg_dest_out <= c_pc_plus4; |
when c_from_imm_shift16 => |
reg_dest_out <= imm_in & ZERO(15 downto 0); |
-- when from_reg_source_nez => |
--???? |
-- when from_reg_source_eqz => |
--???? |
when others => |
reg_dest_out <= c_bus; |
end case; |
end process; |
|
pc_mux: process(branch_func, reg_source, reg_target) |
variable is_equal : std_logic; |
begin |
if reg_source = reg_target then |
is_equal := '1'; |
else |
is_equal := '0'; |
end if; |
case branch_func is |
when branch_ltz => |
take_branch <= reg_source(31); |
when branch_lez => |
take_branch <= reg_source(31) or is_equal; |
when branch_eq => |
take_branch <= is_equal; |
when branch_ne => |
take_branch <= not is_equal; |
when branch_gez => |
take_branch <= not reg_source(31); |
when branch_gtz => |
take_branch <= not reg_source(31) and not is_equal; |
when branch_yes => |
take_branch <= '1'; |
when others => |
take_branch <= is_equal; |
end case; |
end process; |
|
end; --architecture logic |
|
/vhdl/pc_next.vhd
0,0 → 1,68
--------------------------------------------------------------------- |
-- TITLE: Program Counter Next |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 2/8/01 |
-- FILENAME: pc_next.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the Program Counter logic. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity pc_next is |
port(clk : in std_logic; |
reset_in : in std_logic; |
pc_new : in std_logic_vector(31 downto 2); |
take_branch : in std_logic; |
pause_in : in std_logic; |
opcode25_0 : in std_logic_vector(25 downto 0); |
pc_source : in pc_source_type; |
pc_out : out std_logic_vector(31 downto 0); |
pc_out_plus4 : out std_logic_vector(31 downto 0)); |
end; --pc_next |
|
architecture logic of pc_next is |
-- type pc_source_type is (from_inc4, from_opcode25_0, from_branch, |
-- from_lbranch); |
signal pc_reg : std_logic_vector(31 downto 2); --:= ZERO(31 downto 2); |
begin |
|
pc_next: process(clk, reset_in, pc_new, take_branch, pause_in, |
opcode25_0, pc_source, pc_reg) |
variable pc_inc, pc_next : std_logic_vector(31 downto 2); |
begin |
pc_inc := bv_increment(pc_reg); --pc_reg+1 |
|
case pc_source is |
when from_inc4 => |
pc_next := pc_inc; |
when from_opcode25_0 => |
pc_next := pc_reg(31 downto 28) & opcode25_0; |
when others => --from_branch | from_lbranch => |
if take_branch = '1' then |
pc_next := pc_new; |
else |
pc_next := pc_inc; |
end if; |
end case; |
|
if pause_in = '1' then |
pc_next := pc_reg; |
end if; |
|
if reset_in = '1' then |
pc_reg <= ZERO(31 downto 2); |
elsif rising_edge(clk) then |
pc_reg <= pc_next; |
end if; |
|
pc_out <= pc_reg & "00"; |
pc_out_plus4 <= pc_inc & "00"; |
end process; |
|
end; --logic |
|
/vhdl/uart.vhd
0,0 → 1,113
--------------------------------------------------------------------- |
-- TITLE: UART |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 5/29/02 |
-- FILENAME: uart.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- Implements the UART. |
-- Stalls the CPU until the charater has been transmitted. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_misc.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_textio.all; |
use ieee.std_logic_unsigned.all; |
use std.textio.all; |
use work.mlite_pack.all; |
|
entity uart is |
generic(log_file : string := "UNUSED"); |
port(clk : in std_logic; |
reset : in std_logic; |
uart_sel : in std_logic; |
data : in std_logic_vector(7 downto 0); |
uart_read : in std_logic; |
uart_write : out std_logic; |
pause : out std_logic); |
end; --entity ram |
|
architecture logic of uart is |
signal data_reg : std_logic_vector(8 downto 0); |
signal bits_reg : std_logic_vector(3 downto 0); |
signal div_reg : std_logic_vector(9 downto 0); |
begin |
|
uart_proc: process(clk, reset, data_reg, bits_reg, div_reg, uart_sel, data) |
constant DIV_VALUE : std_logic_vector(9 downto 0) := |
"0100011110"; --33MHz/2/57600Hz = 0x11e |
-- "0000000010"; --for debug |
variable data_next : std_logic_vector(8 downto 0); |
variable bits_next : std_logic_vector(3 downto 0); |
variable div_next : std_logic_vector(9 downto 0); |
begin |
data_next := data_reg; |
bits_next := bits_reg; |
div_next := div_reg; |
|
if uart_sel = '1' then |
data_next := data & '0'; |
bits_next := "1010"; |
div_next := ZERO(9 downto 0); |
elsif div_reg = DIV_VALUE then |
data_next := '1' & data_reg(8 downto 1); |
if bits_reg /= "0000" then |
bits_next := bits_reg - 1; |
end if; |
div_next := ZERO(9 downto 0); |
else |
div_next := div_reg + 1; |
end if; |
|
if reset = '1' then |
data_reg <= ZERO(8 downto 0); |
bits_reg <= "0000"; |
div_reg <= ZERO(9 downto 0); |
elsif rising_edge(clk) then |
data_reg <= data_next; |
bits_reg <= bits_next; |
div_reg <= div_next; |
end if; |
|
uart_write <= data_reg(0); |
if uart_sel = '0' and bits_reg /= "0000" |
and log_file = "UNUSED" |
then |
pause <= '1'; |
else |
pause <= '0'; |
end if; |
end process; |
|
uart_logger: |
if log_file /= "UNUSED" generate |
uart_proc: process(clk, uart_sel, data) |
file store_file : text is out log_file; |
variable hex_file_line : line; |
variable c : character; |
variable index : natural; |
variable line_length : natural := 0; |
begin |
if rising_edge(clk) then |
if uart_sel = '1' then |
index := conv_integer(data(6 downto 0)); |
if index /= 10 then |
c := character'val(index); |
write(hex_file_line, c); |
line_length := line_length + 1; |
end if; |
if index = 10 or line_length >= 72 then |
--The following line had to be commented out for synthesis |
writeline(store_file, hex_file_line); |
line_length := 0; |
end if; |
end if; --uart_sel |
end if; --rising_edge(clk) |
end process; --uart_proc |
end generate; --uart_logger |
|
end; --architecture logic |
|
/vhdl/plasma_if.vhd
0,0 → 1,82
--------------------------------------------------------------------- |
-- TITLE: Plamsa Interface (clock divider and interface to FPGA board) |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 6/6/02 |
-- FILENAME: plasma_if.vhd |
-- PROJECT: Plasma CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- This entity divides the clock by two and interfaces to the |
-- Altera EP20K200EFC484-2X FPGA board. |
--------------------------------------------------------------------- |
library ieee; |
use ieee.std_logic_1164.all; |
use work.mlite_pack.all; |
|
entity plasma_if is |
generic(memory_type : string := "ALTERA"; |
log_file : string := "UNUSED"); |
port(clk_in : in std_logic; |
reset_n : in std_logic; |
uart_read : in std_logic; |
uart_write : out std_logic; |
|
address : out std_logic_vector(31 downto 0); |
data : out std_logic_vector(31 downto 0); |
we_n : out std_logic; |
oe_n : out std_logic; |
be_n : out std_logic_vector(3 downto 0); |
sram0_cs_n : out std_logic; |
sram1_cs_n : out std_logic); |
end; --entity plasma_if |
|
architecture logic of plasma_if is |
signal clk_reg : std_logic; |
signal reset_in : std_logic; |
signal intr_in : std_logic; |
signal mem_address : std_logic_vector(31 downto 0); |
signal mem_pause_in : std_logic; |
signal write_enable : std_logic; |
signal mem_byte_sel : std_logic_vector(3 downto 0); |
begin --architecture |
reset_in <= not reset_n; |
intr_in <= '0'; |
mem_pause_in <= '0'; |
|
address <= mem_address; |
we_n <= not write_enable; |
oe_n <= write_enable; |
be_n <= not mem_byte_sel; |
sram0_cs_n <= not mem_address(16); |
sram1_cs_n <= not mem_address(16); |
|
--convert 33MHz clock to 16.5MHz clock |
clk_div: process(clk_in, reset_in, clk_reg) |
begin |
if reset_in = '1' then |
clk_reg <= '0'; |
elsif rising_edge(clk_in) then |
clk_reg <= not clk_reg; |
end if; |
end process; --clk_div |
|
u1_plama: plasma |
generic map (memory_type => memory_type, |
log_file => log_file) |
PORT MAP ( |
clk_in => clk_reg, |
reset_in => reset_in, |
intr_in => intr_in, |
|
uart_read => uart_read, |
uart_write => uart_write, |
|
mem_address_out => mem_address, |
mem_data => data, |
mem_byte_sel_out => mem_byte_sel, |
mem_write_out => write_enable, |
mem_pause_in => mem_pause_in); |
|
end; --architecture logic |
|