Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Jessica Hawkwell
/
kcpu
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
2
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 78af4d11
authored
Oct 01, 2017
by
Jessica Hawkwell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
started preliminary support for interrupts, stacks, and function calls
1 parent
c44caf9d
Pipeline
#211
passed
in 1 minute 8 seconds
Changes
21
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
507 additions
and
275 deletions
.gitignore
src/main/java/me/felinewith/kcpu/KBoard.java
src/main/java/me/felinewith/kcpu/Kasm.java
src/main/java/me/felinewith/kcpu/Kcpu.java
src/main/java/me/felinewith/kcpu/Kemulator.java
src/main/java/me/felinewith/kcpu/hardware/Kmcu.java
src/main/java/me/felinewith/kcpu/interfaces/IDevice.java
src/main/java/me/felinewith/kcpu/interfaces/IMemory.java
src/main/java/me/felinewith/kcpu/memory/BootRom.java
src/main/java/me/felinewith/kcpu/memory/Buffer.java
src/main/java/me/felinewith/kcpu/opcodes/Memory.java
src/main/java/me/felinewith/kcpu/opcodes/OpDirector.java
src/main/java/me/felinewith/kcpu/util/BaseDevice.java
src/main/java/me/felinewith/kcpu/util/BaseMemory.java
src/main/java/me/felinewith/kcpu/util/CPUStoppedException.java
src/main/java/me/felinewith/kcpu/util/HardwareExec.java
src/main/java/me/felinewith/kcpu/util/HardwareMemIrq.java
src/main/java/me/felinewith/kcpu/util/HardwareSendIrq.java → src/main/java/me/felinewith/kcpu/util/HardwareRecvIrq.java
src/main/java/me/felinewith/kcpu/util/helpers/ValueHelper.java
src/main/java/me/felinewith/kcpu/util/helpers/ValueType.java
test.kasm
.gitignore
View file @
78af4d1
# project-specific stuffs
*.mem
*.mem
.txt
*.bin
*.kc
...
...
src/main/java/me/felinewith/kcpu/KBoard.java
View file @
78af4d1
...
...
@@ -13,8 +13,9 @@ import me.felinewith.kcpu.hardware.Kmcu;
import
me.felinewith.kcpu.interfaces.IDevice
;
import
me.felinewith.kcpu.interfaces.IMemory
;
import
me.felinewith.kcpu.util.BaseDevice
;
import
me.felinewith.kcpu.util.
HardwareExec
;
import
me.felinewith.kcpu.util.
CPUStoppedException
;
import
me.felinewith.kcpu.util.HardwareMemIrq
;
import
me.felinewith.kcpu.util.HardwareRecvIrq
;
/**
*
...
...
@@ -56,45 +57,66 @@ public class KBoard extends BaseDevice implements IMemory {
System
.
out
.
println
(
"CPU up..."
);
while
(
cpu
.
workCycle
()
!=
0xff
)
{
Thread
.
yield
();
try
{
while
(
true
)
{
cpu
.
workCycle
();
Thread
.
yield
();
}
}
catch
(
CPUStoppedException
x
)
{}
System
.
err
.
println
(
"CPU Stopped [zpwr]"
);
tpe
.
shutdown
();
System
.
err
.
println
(
"Timers stopped"
);
int
a
;
for
(
a
=
0
;
a
<=
0xf
;
a
++)
{
if
(
devices
[
a
]
!=
null
)
{
devices
[
a
].
powerOff
();
System
.
err
.
println
(
String
.
format
(
"device %x stopped"
,
a
));
}
if
(
memDevs
[
a
]
!=
null
)
{
memDevs
[
a
].
powerOff
();
System
.
err
.
println
(
String
.
format
(
"memdev %x stopped"
,
a
));
}
}
dumpEverything
();
}
@Override
public
void
memIrq
(
short
addr
)
{
@Override
public
void
memIrq
(
short
addr
,
byte
irq
)
{
short
dev
=
checkDevice
(
addr
);
short
rdev
=
(
short
)(
0x0f
&
dev
);
if
(
dev
==
0x7f
)
{
devices
[
0
].
memIrq
(
addr
);
}
StackTraceElement
ste
=
Thread
.
currentThread
().
getStackTrace
()[
1
];
String
className
=
ste
.
getClassName
();
int
sendIrq
=
16
;
int
a
;
for
(
a
=
0
;
a
<
16
;
a
++)
{
if
(
devices
[
a
].
getClass
().
getCanonicalName
().
equals
(
className
))
{
sendIrq
=
a
;
break
;
}
}
if
(
dev
==
0x7f
)
{
devices
[
0
].
memIrq
(
addr
,
(
byte
)
sendIrq
);
}
else
if
(
dev
<=
0x0f
)
{
short
devOff
=
deviceMaps
[
rdev
].
getOffset
();
short
devAddr
=
(
short
)(
addr
-
devOff
);
tpe
.
execute
(
new
HardwareMemIrq
(
devices
[
rdev
],
devAddr
));
tpe
.
execute
(
new
HardwareMemIrq
(
devices
[
rdev
],
devAddr
,
(
byte
)
sendIrq
));
}
else
if
(
0x10
<=
dev
&&
dev
<=
0x1f
)
{
short
devOff
=
memDevMaps
[
rdev
].
getOffset
();
short
devAddr
=
(
short
)(
addr
-
devOff
);
tpe
.
execute
(
new
HardwareMemIrq
(
memDevs
[
rdev
],
devAddr
));
tpe
.
execute
(
new
HardwareMemIrq
(
memDevs
[
rdev
],
devAddr
,
(
byte
)
sendIrq
));
}
}
@Override
public
void
sendIrq
(
byte
irq
)
{
if
(
irq
>=
16
)
{
return
;
}
if
(
devices
[
irq
]
!=
null
)
{
tpe
.
execute
(
new
HardwareExec
(
devices
[
irq
]));
}
StackTraceElement
ste
=
Thread
.
currentThread
().
getStackTrace
()[
1
];
String
className
=
ste
.
getClassName
();
int
sendIrq
=
16
;
int
a
;
for
(
a
=
0
;
a
<
16
;
a
++)
{
if
(
devices
[
a
].
getClass
().
getCanonicalName
().
equals
(
className
))
{
sendIrq
=
a
;
break
;
}
}
if
(
devices
[
irq
]
!=
null
)
{
tpe
.
execute
(
new
HardwareRecvIrq
(
devices
[
irq
],
(
byte
)
sendIrq
));
}
}
@Override
public
short
length
()
{
return
(
short
)
memory
.
length
;
};
...
...
@@ -233,9 +255,6 @@ public class KBoard extends BaseDevice implements IMemory {
}
}
@Override
public
void
exec
()
{
}
public
void
dumpEverything
()
{
dumpMemory
(
"system"
,
memory
);
int
a
;
...
...
@@ -256,7 +275,7 @@ public class KBoard extends BaseDevice implements IMemory {
dumpMemory
(
filename
,
temp
);
}
public
void
dumpMemory
(
String
filename
,
byte
[]
mem
)
{
File
f
=
new
File
(
filename
.
concat
(
".mem"
));
File
f
=
new
File
(
filename
.
concat
(
".mem
.txt
"
));
try
{
System
.
out
.
println
(
String
.
format
(
"Writing %s"
,
f
.
getCanonicalPath
()));
}
catch
(
IOException
x
)
{}
try
(
FileWriter
fw
=
new
FileWriter
(
f
))
{
int
max
=
mem
.
length
;
...
...
src/main/java/me/felinewith/kcpu/Kasm.java
View file @
78af4d1
...
...
@@ -3,18 +3,22 @@ package me.felinewith.kcpu;
import
java.io.BufferedReader
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.PrintStream
;
import
java.util.Arrays
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
me.felinewith.kcpu.hardware.kmcu.KmcuOpCodes
;
import
me.felinewith.kcpu.opcodes.OpDirector
;
import
me.felinewith.kcpu.util.Converter
;
import
me.felinewith.kcpu.util.helpers.ValueType
;
import
org.apache.commons.cli.CommandLine
;
import
org.apache.commons.cli.CommandLineParser
;
import
org.apache.commons.cli.DefaultParser
;
import
org.apache.commons.cli.HelpFormatter
;
import
org.apache.commons.cli.Option
;
import
org.apache.commons.cli.Options
;
import
org.apache.commons.cli.ParseException
;
...
...
@@ -25,89 +29,259 @@ import org.apache.commons.cli.ParseException;
public
class
Kasm
{
private
static
PrintStream
outer
;
private
static
boolean
verbose
=
false
;
public
static
void
main
(
String
[]
args
)
{
setOuter
(
System
.
out
);
Options
opts
=
new
Options
();
opts
.
addOption
(
"b"
,
"base"
,
true
,
"Base address for binary"
);
opts
.
addOption
(
"co"
,
"cpu-opcodes"
,
false
,
"Displays supported CPU opcodes"
);
opts
.
addOption
(
"mo"
,
"mcu-opcodes"
,
false
,
"Displays supported MCU opcodes"
);
opts
.
addOption
(
"v"
,
"verbose"
,
false
,
"Verbose output."
);
opts
.
addOption
(
"kasm"
,
false
,
"Ignored."
);
opts
.
addOption
(
"help"
,
"Show this help"
);
opts
.
addOption
(
Option
.
builder
(
"b"
).
longOpt
(
"base"
)
.
desc
(
"Program's base address. Emitted code will assume it is loaded to this address."
)
.
hasArg
(
true
)
.
argName
(
"addr"
)
.
numberOfArgs
(
1
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
(
"c"
).
longOpt
(
"cpu"
)
.
desc
(
"Displays suppoted CPU opcodes"
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
(
"m"
).
longOpt
(
"mcu"
)
.
desc
(
"Displays suported MCU opcodes."
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
(
"v"
).
longOpt
(
"verbose"
)
.
desc
(
"Verbose output."
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
().
longOpt
(
"kasm"
)
.
desc
(
"This option is ignored."
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
(
"h"
).
longOpt
(
"help"
)
.
desc
(
"Shows this help."
)
.
build
()
);
opts
.
addOption
(
Option
.
builder
(
"o"
).
longOpt
(
"output"
)
.
desc
(
"Filename to use for building a single output file."
)
.
hasArg
()
.
argName
(
"file"
)
.
numberOfArgs
(
1
)
.
build
()
);
String
[]
files
=
Arrays
.
copyOf
(
args
,
args
.
length
);
KasmBuilder
kb
=
Kasm
.
builder
();
CommandLineParser
parser
=
new
DefaultParser
();
try
{
CommandLine
cli
=
parser
.
parse
(
opts
,
args
);
if
(
cli
.
hasOption
(
"help"
)
||
cli
.
hasOption
(
"c
o"
)
||
cli
.
hasOption
(
"mo
"
))
{
if
(
cli
.
hasOption
(
"help"
)
||
cli
.
hasOption
(
"c
"
)
||
cli
.
hasOption
(
"m
"
))
{
if
(
cli
.
hasOption
(
"help"
))
{
HelpFormatter
hf
=
new
HelpFormatter
();
hf
.
printHelp
(
"kasm [options] [kasm ...]"
,
""
,
opts
,
"Non-KASM files may be ignored."
,
false
);
}
if
(
cli
.
hasOption
(
"c
o
"
))
{
if
(
cli
.
hasOption
(
"c
pu
"
))
{
logln
(
"Supported CPU Opcodes:"
);
for
(
OpDirector
oc
:
OpDirector
.
values
())
{
logln
(
"\t[%10s] %s"
,
oc
.
name
(),
oc
.
getDescription
());
}
logln
(
""
);
}
if
(
cli
.
hasOption
(
"m
o
"
))
{
if
(
cli
.
hasOption
(
"m
cu
"
))
{
logln
(
"Supported MCU Opcodes:"
);
for
(
KmcuOpCodes
oc
:
KmcuOpCodes
.
values
())
{
logln
(
"\t
%04x -> [%10s]"
,
oc
.
getOpcode
(),
oc
.
name
());
logln
(
"\t
[%10s] %s"
,
oc
.
name
(),
oc
.
getDescription
());
}
logln
(
""
);
}
return
;
}
if
(
cli
.
hasOption
(
"v"
))
{
verbose
=
true
;
}
if
(
cli
.
hasOption
(
"verbose"
))
{
kb
.
setVerbose
(
true
);
}
if
(
cli
.
hasOption
(
"base"
))
{
kb
.
setBASEaddr
(
Short
.
valueOf
(
cli
.
getOptionValue
(
"base"
)));
}
if
(
cli
.
hasOption
(
"output"
))
{
kb
.
setFile
(
cli
.
getOptionValue
(
"output"
));
}
files
=
cli
.
getArgs
();
}
catch
(
ParseException
x
)
{
logln
(
"Parser error: %s"
,
x
.
getMessage
());
HelpFormatter
hf
=
new
HelpFormatter
();
hf
.
printHelp
(
"kasm [options] [kasm files]"
,
"Header"
,
opts
,
"Footer\nNote: Non-KASM text files may be ignored."
,
true
);
hf
.
printHelp
(
"kasm [options] [kasm files]"
,
"Header"
,
opts
,
"Note: Non-KASM text files may be ignored."
,
true
);
return
;
}
for
(
String
a
:
args
)
{
Kasm
kasm
=
kb
.
build
();
for
(
String
a
:
files
)
{
if
(
a
.
endsWith
(
".kasm"
)
)
{
try
{
assemble
(
a
);
}
try
{
kasm
.
assemble
(
a
);
kasm
.
reset
();
}
catch
(
IOException
x
)
{}
}
}
kasm
.
close
();
}
static
void
assemble
(
String
filename
)
throws
IOException
{
assemble
(
new
File
(
filename
));}
static
void
assemble
(
File
file
)
throws
IOException
{
File
out
=
new
File
(
file
.
getCanonicalPath
().
concat
(
".kc"
));
/**
* @return the outer
*/
public
static
PrintStream
getOuter
()
{
return
outer
;
}
logln
(
"\nInput : %s\nOutput: %s"
,
file
.
getCanonicalPath
(),
out
.
getCanonicalPath
());
FileInputStream
fis
=
new
FileInputStream
(
file
);
FileOutputStream
fos
=
new
FileOutputStream
(
out
);
/**
* @param aOuter the outer to set
*/
public
static
void
setOuter
(
PrintStream
aOuter
)
{
outer
=
aOuter
;
}
InputStreamReader
isr
=
new
InputStreamReader
(
fis
);
BufferedReader
br
=
new
BufferedReader
(
isr
);
private
static
void
log
(
String
format
,
Object
...
vals
)
{
if
(
outer
==
null
)
{
return
;
}
outer
.
print
(
String
.
format
(
format
,
vals
));
}
private
static
void
logln
(
String
format
,
Object
...
vals
)
{
if
(
outer
==
null
)
{
return
;
}
outer
.
println
(
String
.
format
(
format
,
vals
));
}
public
static
KasmBuilder
builder
()
{
return
new
Kasm
.
KasmBuilder
();
}
private
short
BASEaddr
;
private
short
mark
;
private
boolean
verbose
;
private
File
outFile
=
null
;
private
FileOutputStream
fileOutputStream
=
null
;
private
ByteArrayOutputStream
baos
;
private
short
pc
;
private
Kasm
()
{
}
private
Kasm
(
KasmBuilder
builder
)
{
BASEaddr
=
builder
.
BASEaddr
;
if
(
builder
.
file
!=
null
)
{
outFile
=
builder
.
file
;
try
{
fileOutputStream
=
new
FileOutputStream
(
outFile
);
}
catch
(
IOException
x
)
{}
}
verbose
=
builder
.
verbose
;
baos
=
new
ByteArrayOutputStream
();
}
private
String
stripType
(
String
input
)
{
if
(
input
.
contains
(
"."
))
{
return
input
.
substring
(
input
.
indexOf
(
'.'
)
+
1
);
}
switch
(
input
.
charAt
(
0
))
{
case
'R'
:
case
'r'
:
case
'%'
:
case
'$'
:
return
input
.
substring
(
1
);
}
return
input
;
}
private
short
asmType
(
String
input
)
{
String
test
=
input
.
toLowerCase
();
if
(
test
.
startsWith
(
"d."
))
{
return
ValueType
.
D
.
getValue
();
}
else
if
(
test
.
startsWith
(
"r"
)
||
test
.
startsWith
(
"r."
))
{
return
ValueType
.
R
.
getValue
();
}
else
if
(
test
.
startsWith
(
"%"
)
||
test
.
startsWith
(
"ad."
))
{
return
ValueType
.
AD
.
getValue
();
}
else
if
(
test
.
startsWith
(
"$"
)
||
test
.
startsWith
(
"ar."
))
{
return
ValueType
.
AR
.
getValue
();
}
return
ValueType
.
D
.
getValue
();
}
private
short
numberize
(
String
input
)
{
String
temp
=
stripType
(
input
).
toUpperCase
();
String
[]
pt
;
int
tmp
;
// remove underscores, which are useful in reading numbers in code
if
(
temp
.
contains
(
"_"
))
{
temp
=
temp
.
replaceAll
(
"_"
,
""
);
}
// replace assembler keywords with numbers
if
(
temp
.
contains
(
"BASE"
))
{
temp
=
temp
.
replaceAll
(
"BASE"
,
String
.
format
(
"%d"
,
BASEaddr
));
}
if
(
temp
.
contains
(
"MARK"
))
{
temp
=
temp
.
replaceAll
(
"MARK"
,
String
.
format
(
"%d"
,
mark
));
}
Pattern
p
=
Pattern
.
compile
(
"([0-9a-f]+),([0-9]+)"
,
Pattern
.
CASE_INSENSITIVE
);
Matcher
m
=
p
.
matcher
(
temp
);
// convert radix'd numbers
short
radix
;
while
(
m
.
find
())
{
radix
=
Short
.
valueOf
(
m
.
group
(
2
),
10
);
tmp
=
Integer
.
valueOf
(
m
.
group
(
1
),
radix
);
temp
=
temp
.
replace
(
m
.
group
(),
String
.
format
(
"%d"
,
(
short
)(
0xffff
&
tmp
)));
m
.
reset
(
temp
);
}
// perform any required math
p
=
Pattern
.
compile
(
"([0-9a-f]+)([-+*\\/])([0-9a-f]+)"
,
Pattern
.
CASE_INSENSITIVE
);
m
=
p
.
matcher
(
temp
);
while
(
m
.
find
())
{
switch
(
m
.
group
(
2
))
{
case
"+"
:
tmp
=
Integer
.
valueOf
(
m
.
group
(
1
))
+
Integer
.
valueOf
(
m
.
group
(
3
));
temp
=
temp
.
replace
(
m
.
group
(),
String
.
format
(
"%d"
,
(
short
)(
0xffff
&
tmp
)));
break
;
case
"-"
:
tmp
=
Integer
.
valueOf
(
m
.
group
(
1
))
-
Integer
.
valueOf
(
m
.
group
(
3
));
temp
=
temp
.
replace
(
m
.
group
(),
String
.
format
(
"%d"
,
(
short
)(
0xffff
&
tmp
)));
break
;
case
"*"
:
tmp
=
Integer
.
valueOf
(
m
.
group
(
1
))
*
Integer
.
valueOf
(
m
.
group
(
3
));
temp
=
temp
.
replace
(
m
.
group
(),
String
.
format
(
"%d"
,
(
short
)(
0xffff
&
tmp
)));
break
;
case
"/"
:
tmp
=
Integer
.
valueOf
(
m
.
group
(
1
))
/
Integer
.
valueOf
(
m
.
group
(
3
));
temp
=
temp
.
replace
(
m
.
group
(),
String
.
format
(
"%d"
,
(
short
)(
0xffff
&
tmp
)));
break
;
}
m
.
reset
(
temp
);
}
return
(
short
)(
0xffff
&
Integer
.
valueOf
(
temp
));
}
void
assemble
(
String
filename
)
throws
IOException
{
assemble
(
new
File
(
filename
));}
void
assemble
(
File
file
)
throws
IOException
{
String
fn
=
file
.
getCanonicalPath
();
fn
=
fn
.
substring
(
0
,
fn
.
lastIndexOf
(
'.'
));
File
out
=
new
File
(
String
.
format
(
"%s.kc"
,
fn
));
logln
(
"\nInput : %s\nOutput: %s"
,
file
.
getCanonicalPath
(),
(
outFile
==
null
)?
out
.
getCanonicalPath
():
outFile
.
getCanonicalPath
());
readFromFile
(
file
);
sendToFile
(
out
);
}
public
void
readFromFile
(
String
filename
)
throws
IOException
{
readFromFile
(
new
File
(
filename
));}
public
void
readFromFile
(
File
file
)
throws
IOException
{
FileReader
fr
=
new
FileReader
(
file
);
BufferedReader
br
=
new
BufferedReader
(
fr
);
String
line
;
byte
[]
temp
;
int
a
;
while
((
line
=
br
.
readLine
())
!=
null
)
{
temp
=
compile
(
line
);
fos
.
write
(
temp
);
compile
(
line
);
}
fos
.
flush
();
fos
.
close
();
}
public
void
sendToFile
(
String
filename
)
throws
IOException
{
sendToFile
(
new
File
(
filename
));
}
public
void
sendToFile
(
File
file
)
throws
IOException
{
if
(
outFile
==
null
)
{
baos
.
writeTo
(
new
FileOutputStream
(
file
));
}
else
{
baos
.
writeTo
(
fileOutputStream
);
}
baos
.
reset
();
}
br
.
close
();
isr
.
close
();
fis
.
close
();
public
void
compile
(
String
[]
kasm
)
{
for
(
String
s
:
kasm
)
{
compile
(
s
);
}
}
public
void
compile
(
String
kasm
)
{
byte
[]
temp
=
compileSegment
(
kasm
);
baos
.
write
(
temp
,
0
,
temp
.
length
);
}
static
public
byte
[]
compile
(
String
kasm
)
{
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
();
public
byte
[]
compileSegment
(
String
[]
kasm
)
{
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
byte
[]
temp
;
for
(
String
s
:
kasm
)
{
temp
=
compileSegment
(
s
);
output
.
write
(
temp
,
0
,
temp
.
length
);
}
return
output
.
toByteArray
();
}
public
byte
[]
compileSegment
(
String
kasm
)
{
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
if
(
kasm
.
startsWith
(
"#"
)
||
kasm
.
startsWith
(
"//"
)
||
kasm
.
length
()
==
0
)
{}
else
{
if
(
kasm
.
contains
(
"#"
))
{
kasm
=
kasm
.
substring
(
0
,
kasm
.
indexOf
(
"#"
)
-
1
);
}
if
(
kasm
.
contains
(
"//"
))
{
kasm
=
kasm
.
substring
(
0
,
kasm
.
indexOf
(
"//"
)
-
1
);
}
String
[]
parts
;
OpDirector
opcode
;
short
ref
=
0
;
...
...
@@ -116,18 +290,27 @@ public class Kasm {
else
{
parts
=
new
String
[]{
kasm
};
}
parts
[
0
]
=
parts
[
0
].
toUpperCase
();
if
(
parts
[
0
].
equals
(
"FILL"
))
{
if
(
parts
[
0
].
equals
(
"MARK"
))
{
mark
=
pc
;
return
new
byte
[
0
];
}
else
if
(
parts
[
0
].
equals
(
"FILL"
))
{
int
a
;
int
max
=
numberize
(
parts
[
1
]);
byte
fill
=
0
;
if
(
parts
.
length
>=
3
)
{
fill
=
(
byte
)
numberize
(
parts
[
2
]);
}
for
(
a
=
0
;
a
<
max
;
a
++)
{
baos
.
write
(
fill
);
}
return
baos
.
toByteArray
();
if
(
parts
.
length
>=
3
)
{
fill
=
(
byte
)(
0xff
&
numberize
(
parts
[
2
]));
}
byte
[]
bytes
=
compileSegment
(
String
.
format
(
"jmpu %d"
,
max
));
output
.
write
(
bytes
,
0
,
bytes
.
length
);
for
(
a
=
0
;
a
<
max
;
a
++)
{
output
.
write
(
fill
);
}
pc
+=
output
.
size
();
return
output
.
toByteArray
();
}
else
{
opcode
=
OpDirector
.
valueOf
(
parts
[
0
]);
if
(
verbose
)
{
log
(
"[%10s] "
,
opcode
.
name
());
}
writeShort
(
baos
,
opcode
.
getOpcode
());
writeShort
(
output
,
opcode
.
getOpcode
());
short
plen
=
(
short
)
parts
.
length
;
if
(
plen
>=
5
)
{
plen
=
5
;
}
plen
=
(
short
)(
2
+
(
plen
*
2
));
pc
+=
plen
;
if
(
verbose
)
{
log
(
" : "
);
}
if
(
parts
.
length
>=
2
)
{
ref
+=
asmType
(
parts
[
1
]);
}
...
...
@@ -140,90 +323,53 @@ public class Kasm {
else
if
(
parts
.
length
>=
3
)
{
ref
+=
0x0200
;
}
else
if
(
parts
.
length
>=
2
)
{
ref
+=
0x0100
;
}
writeShort
(
baos
,
ref
);
writeShort
(
output
,
ref
);
if
(
verbose
)
{
log
(
" -> "
);
}
if
(
parts
.
length
>=
2
)
{
writeShort
(
baos
,
numberize
(
parts
[
1
]));
}
if
(
parts
.
length
>=
3
)
{
writeShort
(
baos
,
numberize
(
parts
[
2
]));
}
if
(
parts
.
length
>=
4
)
{
writeShort
(
baos
,
numberize
(
parts
[
3
]));
}
if
(
parts
.
length
>=
5
)
{
writeShort
(
baos
,
numberize
(
parts
[
4
]));
}
if
(
parts
.
length
>=
2
)
{
writeShort
(
output
,
numberize
(
parts
[
1
]));
}
if
(
parts
.
length
>=
3
)
{
writeShort
(
output
,
numberize
(
parts
[
2
]));
}
if
(
parts
.
length
>=
4
)
{
writeShort
(
output
,
numberize
(
parts
[
3
]));
}
if
(
parts
.
length
>=
5
)
{
writeShort
(
output
,
numberize
(
parts
[
4
]));
}
if
(
verbose
)
{
logln
(
""
);
}
}
}
return
baos
.
toByteArray
();
return
output
.
toByteArray
();
}
static
void
writeShort
(
ByteArrayOutputStream
baos
,
short
value
)
{
void
writeShort
(
ByteArrayOutputStream
output
,
short
value
)
{
byte
[]
temp
=
Converter
.
short2bytes
(
value
);
if
(
verbose
)
{
log
(
"%02x%02x "
,
temp
[
0
],
temp
[
1
]);
}
baos
.
write
(
temp
,
0
,
temp
.
length
);
}
static
void
writeShort
(
FileOutputStream
fos
,
short
value
)
throws
IOException
{
byte
[]
v
=
Converter
.
short2bytes
(
value
);
if
(
verbose
)
{
log
(
"[%02x%02x]"
,
v
[
0
],
v
[
1
]);
}
fos
.
write
(
v
);
output
.
write
(
temp
,
0
,
temp
.
length
);
}
static
String
stripType
(
String
input
)
{
if
(
asmType
(
input
)
==
0
)
{
return
input
;
}
return
input
.
substring
(
1
);
}
static
short
asmType
(
String
input
)
{
return
asmType
(
input
.
charAt
(
0
));
}
static
short
asmType
(
char
input
)
{
switch
(
input
)
{
case
'r'
:
return
0x01
;
case
'%'
:
return
0x02
;
case
'$'
:
return
0x03
;
default
:
return
0x00
;
}
}
static
short
numberize
(
String
input
)
{
String
temp
=
stripType
(
input
);
String
[]
pt
;
if
(
temp
.
contains
(
"_"
))
{
temp
=
temp
.
replaceAll
(
"_"
,
""
);
}
if
(
temp
.
contains
(
","
))
{
pt
=
temp
.
split
(
"[,]"
);
short
radix
=
Short
.
valueOf
(
pt
[
1
],
10
);
return
(
short
)(
0xffff
&
Integer
.
valueOf
(
pt
[
0
],
radix
));
public
void
reset
()
{
baos
.
reset
();
}
public
void
close
()
{
if
(
fileOutputStream
!=
null
)
{
try
{
fileOutputStream
.
close
();
}
catch
(
IOException
x
)
{}
}
else
{
return
(
short
)(
0xffff
&
Integer
.
valueOf
(
temp
));
}
}
/**
* @return the outer
*/
public
static
PrintStream
getOuter
()
{
return
outer
;
}
/**
* @param aOuter the outer to set
*/
public
static
void
setOuter
(
PrintStream
aOuter
)
{
outer
=
aOuter
;
}
private
static
void
log
(
String
format
,
Object
...
vals
)
{
if
(
outer
==
null
)
{
return
;
}
outer
.
print
(
String
.
format
(
format
,
vals
));
}
private
static
void
logln
(
String
format
,
Object
...
vals
)
{
if
(
outer
==
null
)
{
return
;
}
outer
.
println
(
String
.
format
(
format
,
vals
));
}
public
static
KasmBuilder
builder
()
{
return
new
Kasm
.
KasmBuilder
();
}
short
BASEaddr
;
private
Kasm
()
{
}
private
Kasm
(
KasmBuilder
builder
)
{
BASEaddr
=
builder
.
BASEaddr
;
}
public
static
class
KasmBuilder
{
short
BASEaddr
;
short
BASEaddr
=
0
;
boolean
verbose
=
false
;
File
file
=
null
;
public
KasmBuilder
()
{
}
public
Kasm
build
()
{
return
new
Kasm
(
this
);
}
public
KasmBuilder
setBASEaddr
(
short
BASEaddr
)
{
this
.
BASEaddr
=
BASEaddr
;
return
this
;
}
public
KasmBuilder
setFile
(
String
file
)
{
String
temp
=
file
;
int
t
=
file
.
lastIndexOf
(
'.'
);
if
(
t
==
-
1
)
{
temp
=
String
.
format
(
"%s.kc"
,
file
);
}
else
if
(!
file
.
substring
(
t
+
1
).
equals
(
"kc"
))
{
temp
=
String
.
format
(
"%s.kc"
,
file
.
substring
(
0
,
t
));
}
return
setFile
(
new
File
(
temp
));
}
public
KasmBuilder
setFile
(
File
file
)
{
this
.
file
=
file
;
return
this
;
}
public
KasmBuilder
setVerbose
(
boolean
verbose
)
{
this
.
verbose
=
verbose
;
return
this
;
}
}
}
src/main/java/me/felinewith/kcpu/Kcpu.java
View file @
78af4d1
package
me
.
felinewith
.
kcpu
;
import
java.io.PrintStream
;
import
java.util.Arrays
;
import
me.felinewith.kcpu.interfaces.IMemory
;
import
me.felinewith.kcpu.opcodes.OpDirector
;
import
me.felinewith.kcpu.util.BaseDevice
;
import
me.felinewith.kcpu.util.CPUStoppedException
;
import
me.felinewith.kcpu.util.Converter
;
import
me.felinewith.kcpu.util.helpers.MemHelper
;
import
me.felinewith.kcpu.util.helpers.ValueHelper
;
import
me.felinewith.kcpu.util.helpers.ValueType
;
...
...
@@ -42,9 +45,20 @@ public class Kcpu extends BaseDevice {
short
[]
registers
;
private
KBoard
kboard
;
Thread
initThread
;
public
Kcpu
(
KBoard
system
)
{
memory
=
new
byte
[
0x0800
];
/**
* memory ranges:
* 0x0000 - 0x00ff : data stack
* 0x0100 - 0x017f : pc stack (return stack)
* 0x0180 - 0x019f : interrupt vectors
* 0x0120 : data stack pointer
* 0x0122 : pc stack pointer
* 0x0124 ~ unused
* 0x01ff : interrupt (boolean value)
*/
memory
=
new
byte
[
0x0200
];
name
=
"Kcpu"
;
settings
=
new
short
[
6
];
kboard
=
system
;
...
...
@@ -54,30 +68,45 @@ public class Kcpu extends BaseDevice {
}
@Override
public
void
init
(
IMemory
system
)
{
initThread
=
Thread
.
currentThread
();
setOuter
(
System
.
err
);
}
@Override
public
void
exec
()
{
workCycle
();
}
// need to prevent other devices from writing to CPU internals
@Override
public
void
write
(
short
offset
,
byte
data
)
{
}
@Override
public
byte
read
(
short
addr
)
{
if
(
(
0xffff
&
addr
)
>
length
()
)
{
return
(
byte
)
0xff
;
}
return
memory
[
0xffff
&
addr
];
}
@Override
public
void
recvIrq
(
byte
irq
)
{
synchronized
(
initThread
)
{
short
[]
regs
=
Arrays
.
copyOf
(
registers
,
registers
.
length
);
short
counter
=
pc
;
if
(
Thread
.
currentThread
().
getId
()
!=
initThread
.
getId
())
{
initThread
.
interrupt
();
regs
=
Arrays
.
copyOf
(
registers
,
registers
.
length
);
counter
=
pc
;
}
@Override
public
void
write
(
short
offset
,
byte
data
)
{
}
@Override
public
void
copy
(
short
addrSrc
,
short
addrDest
,
IMemory
dest
)
{
}
short
start
=
(
short
)((
irq
*
2
)
+
0x0180
);
pc
=
Converter
.
bytes2short
(
new
byte
[]{
memory
[
start
],
memory
[
start
+
1
]});
try
{
while
(
true
)
{
workCycle
();
Thread
.
yield
();
}
}
catch
(
CPUStoppedException
x
)
{}
@Override
public
void
memIrq
(
short
addr
)
{
if
(
0
<=
addr
&&
addr
<=
memory
.
length
)
{
exec
();
}
if
(
Thread
.
currentThread
().
getId
()
!=
initThread
.
getId
())
{
registers
=
Arrays
.
copyOf
(
regs
,
regs
.
length
);
pc
=
counter
;
initThread
.
notify
();
}
}
}
public
int
workCycle
()
{
public
void
workCycle
()
throws
CPUStoppedException
{
if
(
pc
>=
0xfff0
)
{
pc
=
0
;
}
short
inst
=
MemHelper
.
readShort
(
pc
,
kboard
);
short
ref
=
MemHelper
.
readShort
(
pc
+
2
,
kboard
);
short
[]
values
=
new
short
[
4
]
;
if
((
0xffff
&
inst
)
==
0xff
ff
){
log
ln
(
"Break!
"
);
short
[]
values
=
new
short
[
]{(
short
)
0
,
(
short
)
1
,
(
short
)
2
,
(
short
)
3
}
;
if
((
0xffff
&
inst
)
==
0xff
1b
){
log
(
"
"
);
}
switch
(
0x0700
&
ref
)
{
case
0x0700
:
case
0x0600
:
case
0x0500
:
...
...
@@ -96,8 +125,20 @@ public class Kcpu extends BaseDevice {
}
log
(
"%04x : [%10s] %04x ->"
,
pc
,
((
od
==
null
)?
"nop"
:
od
.
name
()),
ref
);
log
(
" %04x %04x %04x %04x "
,
registers
[
0
],
registers
[
1
],
registers
[
2
],
registers
[
3
]);
log
(
" %04x %04x %04x %04x\t\t"
,
registers
[
0
],
registers
[
1
],
registers
[
2
],
registers
[
3
]);
// bring up the program counter
if
(
od
==
null
)
{
pc
+=
12
;
return
;
}
// inc if nop
pc
+=
4
;
pc
+=
(((
0x0700
&
ref
)
>>
8
)
*
2
);
// this works because the value starts counting at 1
switch
(
0x0700
&
ref
)
{
case
0x0000
:
ref
+=
ValueType
.
R
.
getValue
();
case
0x0100
:
ref
+=
(
ValueType
.
R
.
getValue
()
<<
2
);
case
0x0200
:
ref
+=
(
ValueType
.
R
.
getValue
()
<<
4
);
case
0x0300
:
ref
+=
(
ValueType
.
R
.
getValue
()
<<
6
);
}
if
((
0x0700
&
ref
)
>=
0x0100
)
{
log
(
" %2s.%04x"
,
ValueType
.
valueOf
(
ref
,
0
),
values
[
0
]);
}
if
((
0x0700
&
ref
)
>=
0x0200
)
{
log
(
" %2s.%04x"
,
ValueType
.
valueOf
(
ref
,
1
),
values
[
1
]);
}
...
...
@@ -105,72 +146,65 @@ public class Kcpu extends BaseDevice {
if
((
0x0700
&
ref
)
>=
0x0400
)
{
log
(
" %2s.%04x"
,
ValueType
.
valueOf
(
ref
,
3
),
values
[
3
]);
}
logln
(
""
);
if
(
od
==
null
)
{
pc
+=
12
;
return
0
;
}
// inc if nop
pc
+=
4
;
pc
+=
(((
0x0700
&
ref
)
>>
8
)
*
2
);
if
(
od
.
hasHandler
()
)
{
registers
=
od
.
call
(
pc
,
ref
,
registers
,
values
,
kboard
);
return
0
;
return
;
}
short
data
=
ValueHelper
.
readShort
(
0
,
ref
,
registers
,
values
,
kboard
);
switch
(
od
)
{
// device management
case
DEVA:
registers
[
0
]
=
kboard
.
checkDevice
(
data
);
return
0
;
case
DEVD:
kboard
.
detachDevice
(
data
);
return
0
;
case
DEVA:
registers
[
0
]
=
kboard
.
checkDevice
(
data
);
return
;
case
DEVD:
kboard
.
detachDevice
(
data
);
return
;
case
DEVM:
kboard
.
setDeviceRange
(
data
,
ValueHelper
.
readShort
(
1
,
ref
,
registers
,
values
,
kboard
));
return
0
;
return
;
case
DEVP:
KMemoryRange
kmr
=
kboard
.
getDeviceRange
(
data
);
registers
[
0
]
=
kmr
.
getOffset
();
registers
[
1
]
=
kmr
.
getLength
();
return
0
;
return
;
// interrupts
case
IRQD:
kboard
.
sendIrq
((
byte
)(
0x000f
&
data
));
return
0
;
case
IRQM:
kboard
.
memIrq
(
data
);
return
0
;
case
IRQD:
kboard
.
sendIrq
((
byte
)(
0x000f
&
data
));
return
;
case
IRQM:
kboard
.
memIrq
(
data
,
(
byte
)
0
);
return
;
// jumps
case
JMP:
pc
=
(
short
)(
pc
+
(
0xffff
&
data
));
return
0
;
case
JMPA:
pc
=
data
;
return
0
;
case
JMPD:
pc
=
(
short
)(
pc
-
(
0xffff
&
data
));
return
0
;
case
JMP:
case
JMPU:
pc
=
(
short
)(
pc
+
(
0xffff
&
data
));
return
;
case
JMPA:
pc
=
data
;
return
;
case
JMPD:
pc
=
(
short
)(
pc
-
(
0xffff
&
data
));
return
;
case
GPC:
registers
=
ValueHelper
.
writeShort
(
0
,
ref
,
registers
,
values
,
kboard
,
pc
)
;
return
0
;
case
ZPWR:
return
0xff
;
registers
[
0
]
=
pc
;
return
;
case
ZPWR:
throw
new
CPUStoppedException
(
"zpwr"
)
;
}
short
data2
=
ValueHelper
.
readShort
(
1
,
ref
,
registers
,
values
,
kboard
);
short
data3
=
ValueHelper
.
readShort
(
2
,
ref
,
registers
,
values
,
kboard
);
switch
(
od
)
{
// conditionals
case
JE:
if
(
data
==
data2
)
{
pc
+=
data3
;
}
return
0
;
case
JAE:
if
(
data
==
data2
)
{
pc
=
data3
;
}
return
0
;
case
JDE:
if
(
data
==
data2
)
{
pc
-=
data3
;
}
return
0
;
case
JG:
if
(
data
>
data2
)
{
pc
+=
data3
;
}
return
0
;
case
JAG:
if
(
data
>
data2
)
{
pc
=
data3
;
}
return
0
;
case
JDG:
if
(
data
>
data2
)
{
pc
-=
data3
;
}
return
0
;
case
JL:
if
(
data
<
data2
)
{
pc
+=
data3
;
}
return
0
;
case
JAL:
if
(
data
<
data2
)
{
pc
=
data3
;
}
return
0
;
case
JDL:
if
(
data
<
data2
)
{
pc
-=
data3
;
}
return
0
;
case
JGE:
if
(
data
>=
data2
)
{
pc
+=
data3
;
}
return
0
;
case
JAGE:
if
(
data
>=
data2
)
{
pc
=
data3
;
}
return
0
;
case
JDGE:
if
(
data
>=
data2
)
{
pc
-=
data3
;
}
return
0
;
case
JLE:
if
(
data
<=
data2
)
{
pc
+=
data3
;
}
return
0
;
case
JALE:
if
(
data
<=
data2
)
{
pc
=
data3
;
}
return
0
;
case
JDLE:
if
(
data
<=
data2
)
{
pc
-=
data3
;
}
return
0
;
case
JE:
if
(
data
==
data2
)
{
pc
+=
data3
;
}
return
;
case
JAE:
if
(
data
==
data2
)
{
pc
=
data3
;
}
return
;
case
JDE:
if
(
data
==
data2
)
{
pc
-=
data3
;
}
return
;
case
JG:
if
(
data
>
data2
)
{
pc
+=
data3
;
}
return
;
case
JAG:
if
(
data
>
data2
)
{
pc
=
data3
;
}
return
;
case
JDG:
if
(
data
>
data2
)
{
pc
-=
data3
;
}
return
;
case
JL:
if
(
data
<
data2
)
{
pc
+=
data3
;
}
return
;
case
JAL:
if
(
data
<
data2
)
{
pc
=
data3
;
}
return
;
case
JDL:
if
(
data
<
data2
)
{
pc
-=
data3
;
}
return
;
case
JGE:
if
(
data
>=
data2
)
{
pc
+=
data3
;
}
return
;
case
JAGE:
if
(
data
>=
data2
)
{
pc
=
data3
;
}
return
;
case
JDGE:
if
(
data
>=
data2
)
{
pc
-=
data3
;
}
return
;
case
JLE:
if
(
data
<=
data2
)
{
pc
+=
data3
;
}
return
;
case
JALE:
if
(
data
<=
data2
)
{
pc
=
data3
;
}
return
;
case
JDLE:
if
(
data
<=
data2
)
{
pc
-=
data3
;
}
return
;
case
VCMP:
registers
[
0
]
=
0
;
if
(
data
!=
data2
)
{
registers
[
0
]
+=
0x0001
;
}
if
(
data
>=
data2
)
{
registers
[
0
]
+=
0x0002
;
}
if
(
data
==
data2
)
{
registers
[
0
]
+=
0x0004
;
}
if
(
data
<=
data2
)
{
registers
[
0
]
+=
0x0008
;
}
return
0
;
}
return
0
;
}
}
src/main/java/me/felinewith/kcpu/Kemulator.java
View file @
78af4d1
...
...
@@ -30,7 +30,7 @@ public class Kemulator {
ArrayList
<
Option
>
option
=
new
ArrayList
<>();
option
.
add
(
Option
.
builder
(
"b"
)
.
longOpt
(
"bootrom"
)
.
argName
(
"bootrom
.kc
"
)
.
argName
(
"bootrom"
)
.
hasArg
()
.
numberOfArgs
(
8
)
.
build
()
...
...
src/main/java/me/felinewith/kcpu/hardware/Kmcu.java
View file @
78af4d1
package
me
.
felinewith
.
kcpu
.
hardware
;
import
me.felinewith.kcpu.hardware.kmcu.KmcuOp
;
import
java.io.PrintStream
;
import
java.util.Arrays
;
import
me.felinewith.kcpu.
util.Converter
;
import
me.felinewith.kcpu.
hardware.kmcu.KmcuOp
;
import
me.felinewith.kcpu.util.BaseDevice
;
import
me.felinewith.kcpu.util.Converter
;
/**
*
...
...
@@ -38,11 +38,6 @@ public class Kmcu extends BaseDevice {
name
=
"Kmcp"
;
}
@Override
public
void
exec
()
{
workInit
((
short
)
0
);
workInit
((
short
)
1
);
}
private
void
workInit
(
short
setting
)
{
byte
[]
reg
;
if
(
setting
==
0
)
{
reg
=
Arrays
.
copyOfRange
(
memory
,
0
,
7
);
}
...
...
@@ -465,9 +460,15 @@ public class Kmcu extends BaseDevice {
return
output
;
}
@Override
public
void
memIrq
(
short
addr
)
{
if
(
0
<=
addr
&&
addr
<=
memory
.
length
)
{
exec
();
}
@Override
public
void
memIrq
(
short
addr
,
byte
irq
)
{
if
(
0
<=
addr
&&
addr
<=
memory
.
length
)
{
workInit
((
short
)
0
);
workInit
((
short
)
1
);
}
}
@Override
public
void
sendIrq
(
byte
irq
)
{
}
@Override
public
void
recvIrq
(
byte
irq
)
{
workInit
((
short
)
0
);
workInit
((
short
)
1
);
}
}
src/main/java/me/felinewith/kcpu/interfaces/IDevice.java
View file @
78af4d1
...
...
@@ -8,5 +8,5 @@ public interface IDevice extends IMemory {
public
void
init
(
IMemory
board
);
public
abstract
void
sendIrq
(
byte
irq
);
public
void
exec
(
);
public
abstract
void
recvIrq
(
byte
irq
);
}
src/main/java/me/felinewith/kcpu/interfaces/IMemory.java
View file @
78af4d1
...
...
@@ -8,8 +8,7 @@ public interface IMemory {
public
abstract
short
length
();
public
abstract
byte
read
(
short
addr
);
public
abstract
void
write
(
short
addr
,
byte
data
);
public
void
copy
(
short
addrSrc
,
short
addrDest
,
IMemory
dest
);
public
abstract
void
memIrq
(
short
addr
);
public
abstract
void
memIrq
(
short
addr
,
byte
irq
);
public
void
powerOff
();
}
src/main/java/me/felinewith/kcpu/memory/BootRom.java
View file @
78af4d1
...
...
@@ -6,6 +6,7 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.util.Arrays
;
import
me.felinewith.kcpu.Kasm
;
import
me.felinewith.kcpu.Kasm.KasmBuilder
;
import
me.felinewith.kcpu.util.BaseMemory
;
/**
...
...
@@ -15,42 +16,42 @@ import me.felinewith.kcpu.util.BaseMemory;
public
class
BootRom
extends
BaseMemory
{
private
short
writepos
;
private
short
prev
;
private
short
prev2
;
private
boolean
writable
;
public
BootRom
()
{
writepos
=
0
;
prev
=
0
;
prev2
=
0
;
writable
=
false
;
writable
=
true
;
memory
=
new
byte
[
0x1000
];
Arrays
.
fill
(
memory
,
(
byte
)
0xff
);
KasmBuilder
kb
=
Kasm
.
builder
();
kb
.
setBASEaddr
((
short
)
0x1000
);
kb
.
setVerbose
(
false
);
Kasm
kasm
=
kb
.
build
();
// hardcoding some bootrom
writeBytes
(
Kasm
.
compile
(
"movs $0 r2"
));
writeBytes
(
Kasm
.
compile
(
"add r0 16"
));
writeBytes
(
Kasm
.
compile
(
"add r2 1"
));
writeBytes
(
Kasm
.
compile
(
"movs $0 r2"
));
writeBytes
(
Kasm
.
compile
(
"jdl r0 512 22,16"
));
//writeBytes(kasm.compileSegment("movs $0 r2"));
kasm
.
compileSegment
(
"mark"
);
writeBytes
(
kasm
.
compileSegment
(
"add r0 16"
));
writeBytes
(
kasm
.
compileSegment
(
"add r2 1"
));
writeBytes
(
kasm
.
compileSegment
(
"movs $0 r2"
));
writeBytes
(
kasm
.
compileSegment
(
"jdl r0 512 mark"
));
//writeBytes(Kasm.compile("movs r0 0"));
//writeBytes(Kasm.compile("movs r1 0"));
//writeBytes(Kasm.compile("movs r2 0"));
//writeBytes(Kasm.compile("movs r3 0"));
writeBytes
(
Kasm
.
compile
(
"gpc %0300,16
"
));
writeBytes
(
Kasm
.
compile
(
"mov ff00,16 61,16"
));
writeBytes
(
Kasm
.
compile
(
"irqm ff01,16"
));
writeBytes
(
kasm
.
compileSegment
(
"gpc
"
));
writeBytes
(
kasm
.
compileSegment
(
"mov ff00,16 61,16"
));
writeBytes
(
kasm
.
compileSegment
(
"irqm ff01,16"
));
}
@Override
public
void
memIrq
(
short
addr
)
{
writable
=
((
prev2
==
0x4b63
)
&&
(
prev
==
0x7075
)
&&
(
addr
==
0x7f
));
if
((
0xff
&
prev
)
==
0
)
{
prev
+=
addr
;
}
else
if
((
0xff00
&
prev
)
==
0
)
{
prev
=
(
short
)(
prev
<<
8
);
prev
+=
addr
;
}
else
{
prev2
=
prev
;
}
}
// writable at the start, so smart ROMs can rewrite themselves to rearrange stuff
// useful for moving devices around the address space at boot-time
// then a simple program can write a device table into ROM space
// finally, send an interrupt to the ROM device to lock it
@Override
public
void
memIrq
(
short
addr
,
byte
irq
)
{
writable
=
false
;
}
@Override
public
void
write
(
short
addr
,
byte
data
)
{
if
(!
writable
)
{
return
;
}
...
...
src/main/java/me/felinewith/kcpu/memory/Buffer.java
View file @
78af4d1
...
...
@@ -40,7 +40,7 @@ public class Buffer extends BaseMemory {
bufout
=
new
OutputStreamWriter
(
stdout
);
}
@Override
public
void
memIrq
(
short
addr
)
{
@Override
public
void
memIrq
(
short
addr
,
byte
irq
)
{
short
a
;
short
value
;
if
(
addr
<=
0x0f
)
{
...
...
src/main/java/me/felinewith/kcpu/opcodes/Memory.java
View file @
78af4d1
package
me
.
felinewith
.
kcpu
.
opcodes
;
import
me.felinewith.kcpu.util.helpers.ValueHelper
;
import
java.util.Arrays
;
import
me.felinewith.kcpu.interfaces.IMemory
;
import
me.felinewith.kcpu.util.helpers.ValueHelper
;
/**
*
...
...
@@ -11,8 +11,9 @@ import me.felinewith.kcpu.interfaces.IMemory;
public
class
Memory
implements
IOpcodeHandler
{
@Override
public
short
[]
opcode
(
OpDirector
opcode
,
short
pc
,
short
ref
,
short
[]
regs
,
short
[]
values
,
IMemory
memory
)
{
short
data
;
short
[]
output
=
Arrays
.
copyOf
(
regs
,
regs
.
length
);
short
addr
=
ValueHelper
.
readShort
(
0
,
ref
,
output
,
values
,
memory
);
short
data
;
switch
(
opcode
)
{
case
MOV:
case
MOVB:
data
=
ValueHelper
.
readByte
(
1
,
ref
,
output
,
values
,
memory
);
...
...
src/main/java/me/felinewith/kcpu/opcodes/OpDirector.java
View file @
78af4d1
...
...
@@ -18,43 +18,59 @@ public enum OpDirector {
MOV
(
0x0010
,
Memory
.
class
,
"Alias for MOVB"
),
MOVB
(
0x0010
,
Memory
.
class
,
"dest value"
),
MOVS
(
0x0011
,
Memory
.
class
,
"dest value"
),
// stack manipulation
PUSH
(
0x1000
,
"value: push value to stack"
),
POP
(
0x1001
,
"pop value off stack"
),
CALL
(
0x1002
,
"addr: call function at address"
),
RET
(
0x1003
,
"return from function"
),
IRET
(
0x10f0
,
"return from interrupt state (does nothing in normal mode)"
),
// interrupt vector management
IVEC
(
0x10f1
,
"irq addr: set function address for interrupt irq"
),
// cpu stuffies
DEVA
(
0xff00
,
"
n0; get device at address n0
"
),
// get device port from address
DEVD
(
0xff01
,
"
n0: detach device on port n0
"
),
// detach device
DEVM
(
0xff02
,
"
n0 n1: relocate device n0 to address n1
"
),
// relocate device
DEVP
(
0x1003
,
"
n0: get device address for device on port n0
"
),
// get device address from port
DEVA
(
0xff00
,
"
addr; get device at address
"
),
// get device port from address
DEVD
(
0xff01
,
"
port: detach device on port
"
),
// detach device
DEVM
(
0xff02
,
"
port newaddr: relocate device to address
"
),
// relocate device
DEVP
(
0x1003
,
"
port: get device address for device on port
"
),
// get device address from port
IRQD
(
0xff10
,
"n0: send interrupt to port n0"
),
// interrupt to port
IRQM
(
0xff11
,
"n0: send interrupt to memory address n0"
),
// interrupt to memory
// interrupts
IRQD
(
0xff10
,
"port: send interrupt to port"
),
// interrupt to port
IRQM
(
0xff11
,
"addr: send interrupt to memory address"
),
// interrupt to memory
// jumps
JMP
(
0xff18
,
"Alias of JMPU"
),
// jump up
JMPU
(
0xff18
,
"
n0
: jump up n0 addresses"
),
JMPA
(
0xff19
,
"
n0
: jump to address n0"
),
// jump absolute addr
JMPD
(
0xff1a
,
"
n0
: jump down n0 addresses"
),
// jump down
JMPU
(
0xff18
,
"
addr
: jump up n0 addresses"
),
JMPA
(
0xff19
,
"
addr
: jump to address n0"
),
// jump absolute addr
JMPD
(
0xff1a
,
"
addr
: jump down n0 addresses"
),
// jump down
GPC
(
0xff1b
,
"write instruction pointer"
),
// get instruction pointer
// comparisson jumps
JE
(
0xff20
,
"Alias of JUE"
),
// jump if =
JUE
(
0xff20
,
"n0 n1
n2
: jump if n0 == n1, see JMPU"
),
JAE
(
0xff21
,
"n0 n1
n2
: jump if n0 == n1, see JMPA"
),
JDE
(
0xff22
,
"n0 n1
n2
: jump if n0 == n1, see JMPD"
),
JUE
(
0xff20
,
"n0 n1
addr
: jump if n0 == n1, see JMPU"
),
JAE
(
0xff21
,
"n0 n1
addr
: jump if n0 == n1, see JMPA"
),
JDE
(
0xff22
,
"n0 n1
addr
: jump if n0 == n1, see JMPD"
),
JG
(
0xff23
,
"Alias of JUG"
),
// jump if >
JUG
(
0xff23
,
"n0 n1
n2
: jump if n0 > n1, see JMPU"
),
JAG
(
0xff24
,
"n0 n1
n2
: jump if n0 > n1, see JMPA"
),
JDG
(
0xff25
,
"n0 n1
n2
: jump if n0 > n1, see JMPD"
),
JUG
(
0xff23
,
"n0 n1
addr
: jump if n0 > n1, see JMPU"
),
JAG
(
0xff24
,
"n0 n1
addr
: jump if n0 > n1, see JMPA"
),
JDG
(
0xff25
,
"n0 n1
addr
: jump if n0 > n1, see JMPD"
),
JL
(
0xff26
,
"Alias of JUL"
),
// jump if <
JUL
(
0xff26
,
"n0 n1
n2
: jump if n0 < n1, see JMPU"
),
JAL
(
0xff27
,
"n0 n1
n2
: jump if n0 < n1, see JMPA"
),
JDL
(
0xff28
,
"n0 n1
n2
: jump if n0 < n1, see JMPD"
),
JUL
(
0xff26
,
"n0 n1
addr
: jump if n0 < n1, see JMPU"
),
JAL
(
0xff27
,
"n0 n1
addr
: jump if n0 < n1, see JMPA"
),
JDL
(
0xff28
,
"n0 n1
addr
: jump if n0 < n1, see JMPD"
),
JGE
(
0xff29
,
"Alias of JUGE"
),
// jump if >=
JUGE
(
0xff29
,
"n0 n1
n2
: jump if n0 >= n1, see JMPU"
),
JAGE
(
0xff2a
,
"n0 n1
n2
: jump if n0 >= n1, see JMPA"
),
JDGE
(
0xff2b
,
"n0 n1
n2
: jump if n0 >= n1, see JMPD"
),
JUGE
(
0xff29
,
"n0 n1
addr
: jump if n0 >= n1, see JMPU"
),
JAGE
(
0xff2a
,
"n0 n1
addr
: jump if n0 >= n1, see JMPA"
),
JDGE
(
0xff2b
,
"n0 n1
addr
: jump if n0 >= n1, see JMPD"
),
JLE
(
0xff2c
,
"Alias of JULE"
),
// jump if <=
JULE
(
0xff2c
,
"n0 n1 n2: jump if n0 <= n1, see JMPU"
),
JALE
(
0xff2d
,
"n0 n1 n2: jump if n0 <= n1, see JMPA"
),
JDLE
(
0xff2e
,
"n0 n1 n2: jump if n0 <= n1, see JMPD"
),
JULE
(
0xff2c
,
"n0 n1 addr: jump if n0 <= n1, see JMPU"
),
JALE
(
0xff2d
,
"n0 n1 addr: jump if n0 <= n1, see JMPA"
),
JDLE
(
0xff2e
,
"n0 n1 addr: jump if n0 <= n1, see JMPD"
),
// value compare
VCMP
(
0xff2f
,
"n0 n1: performs multiple comparissons of n0 and n1"
),
// power
ZPWR
(
0xffff
,
"Power off"
),
// power off
;
...
...
src/main/java/me/felinewith/kcpu/util/BaseDevice.java
View file @
78af4d1
...
...
@@ -16,16 +16,13 @@ public abstract class BaseDevice extends BaseMemory implements IDevice {
board
=
system
;
}
@Override
public
void
memIrq
(
short
addr
)
{
if
(
0
<=
addr
&&
addr
<=
memory
.
length
)
{
exec
();
}
}
protected
void
sendIrq
()
{
int
addr
=
memory
.
length
-
1
;
sendIrq
(
memory
[
addr
]);
}
@Override
public
void
sendIrq
(
byte
irq
)
{
}
@Override
public
void
recvIrq
(
byte
irq
)
{
}
@Override
public
short
length
()
{
return
(
short
)
memory
.
length
;
}
...
...
src/main/java/me/felinewith/kcpu/util/BaseMemory.java
View file @
78af4d1
...
...
@@ -26,13 +26,7 @@ public abstract class BaseMemory implements IMemory {
memory
[
0xffff
&
addr
]
=
data
;
}
public
final
void
copy
(
int
addrSrc
,
int
addrDest
,
IMemory
dest
)
{
copy
((
short
)
addrSrc
,
(
short
)
addrDest
,
dest
);
}
@Override
public
void
copy
(
short
addrSrc
,
short
addrDest
,
IMemory
dest
)
{
if
(
(
0xffff
&
addrSrc
)
>
length
()
)
{
return
;
}
dest
.
write
(
addrDest
,
read
(
addrSrc
));
}
@Override
public
void
memIrq
(
short
addr
)
{
}
@Override
public
void
memIrq
(
short
addr
,
byte
irq
)
{
}
@Override
public
void
powerOff
()
{
}
}
src/main/java/me/felinewith/kcpu/util/CPUStoppedException.java
0 → 100644
View file @
78af4d1
package
me
.
felinewith
.
kcpu
.
util
;
/**
*
* @author jlhawkwell
*/
public
class
CPUStoppedException
extends
Exception
{
/**
* Creates a new instance of <code>CPUStoppedException</code> without detail message.
*/
public
CPUStoppedException
()
{
}
/**
* Constructs an instance of <code>CPUStoppedException</code> with the specified detail message.
*
* @param msg the detail message.
*/
public
CPUStoppedException
(
String
msg
)
{
super
(
msg
);
}
}
src/main/java/me/felinewith/kcpu/util/HardwareExec.java
deleted
100644 → 0
View file @
c44caf9
package
me
.
felinewith
.
kcpu
.
util
;
import
java.util.TimerTask
;
import
me.felinewith.kcpu.interfaces.IDevice
;
/**
*
* @author jlhawkwell
*/
public
class
HardwareExec
extends
TimerTask
{
IDevice
id
;
public
HardwareExec
(
IDevice
device
)
{
id
=
device
;
}
@Override
public
void
run
()
{
id
.
exec
();
}
}
src/main/java/me/felinewith/kcpu/util/HardwareMemIrq.java
View file @
78af4d1
...
...
@@ -11,10 +11,15 @@ public class HardwareMemIrq extends TimerTask {
IMemory
id
;
short
a
;
byte
i
;
public
HardwareMemIrq
(
IMemory
device
,
short
addr
)
{
public
HardwareMemIrq
(
IMemory
device
,
short
addr
,
byte
irq
)
{
id
=
device
;
a
=
addr
;
i
=
irq
;
}
@Override
public
void
run
()
{
Thread
.
currentThread
().
setName
(
String
.
format
(
"memIRQ-%02x-%x"
,
id
,
Thread
.
currentThread
().
getId
()
));
id
.
memIrq
(
a
,
i
);
}
@Override
public
void
run
()
{
id
.
memIrq
(
a
);
}
}
src/main/java/me/felinewith/kcpu/util/Hardware
Send
Irq.java
→
src/main/java/me/felinewith/kcpu/util/Hardware
Recv
Irq.java
View file @
78af4d1
...
...
@@ -7,14 +7,17 @@ import me.felinewith.kcpu.interfaces.IDevice;
*
* @author jlhawkwell
*/
public
class
Hardware
Send
Irq
extends
TimerTask
{
public
class
Hardware
Recv
Irq
extends
TimerTask
{
IDevice
id
;
byte
i
;
public
Hardware
Send
Irq
(
IDevice
device
,
byte
irq
)
{
public
Hardware
Recv
Irq
(
IDevice
device
,
byte
irq
)
{
id
=
device
;
i
=
irq
;
}
@Override
public
void
run
()
{
id
.
sendIrq
(
i
);
}
@Override
public
void
run
()
{
Thread
.
currentThread
().
setName
(
String
.
format
(
"recvIRQ-%02x_%02x-%x"
,
id
,
i
,
Thread
.
currentThread
().
getId
()
));
id
.
recvIrq
(
i
);
}
}
src/main/java/me/felinewith/kcpu/util/helpers/ValueHelper.java
View file @
78af4d1
...
...
@@ -25,6 +25,7 @@ public class ValueHelper {
case
2
:
cref
=
(
short
)(
0x0030
&
ref
);
break
;
case
3
:
cref
=
(
short
)(
0x00c0
&
ref
);
break
;
}
switch
(
cref
)
{
case
0x0000
:
output
=
values
[
pos
];
break
;
case
0x0001
:
case
0x0004
:
case
0x0010
:
case
0x0040
:
...
...
@@ -55,10 +56,14 @@ public class ValueHelper {
case
2
:
cref
=
(
short
)(
0x0030
&
ref
);
break
;
case
3
:
cref
=
(
short
)(
0x00c0
&
ref
);
break
;
}
// short-circuit write to register if position isn't used in the instruction
if
(
pos
>
((
0x0f00
&
reg
)
>>
8
))
{
cref
=
1
;
}
switch
(
cref
)
{
case
0x0000
:
case
0x0001
:
case
0x0004
:
case
0x0010
:
case
0x0040
:
output
[
reg
]
=
data
;
break
;
case
0x0000
:
case
0x0002
:
case
0x0008
:
case
0x0020
:
case
0x0080
:
MemHelper
.
writeByte
(
values
[
pos
],
data
,
memory
);
break
;
case
0x0003
:
case
0x000c
:
case
0x0030
:
case
0x00c0
:
...
...
@@ -109,10 +114,16 @@ public class ValueHelper {
case
2
:
cref
=
(
short
)(
0x0030
&
ref
);
break
;
case
3
:
cref
=
(
short
)(
0x00c0
&
ref
);
break
;
}
// short-circuit write to register if position isn't used in the instruction
if
(
pos
>
((
0x0f00
&
ref
)
>>
8
))
{
cref
=
1
;
}
switch
(
cref
)
{
case
0x0000
:
case
0x0001
:
case
0x0004
:
case
0x0010
:
case
0x0040
:
output
[
reg
]
=
data
;
break
;
case
0x0000
:
case
0x0002
:
case
0x0008
:
case
0x0020
:
case
0x0080
:
MemHelper
.
writeShort
(
values
[
pos
],
data
,
memory
);
break
;
case
0x0003
:
case
0x000c
:
case
0x0030
:
case
0x00c0
:
...
...
src/main/java/me/felinewith/kcpu/util/helpers/ValueType.java
View file @
78af4d1
...
...
@@ -10,8 +10,8 @@ public enum ValueType {
AD
(
2
),
AR
(
3
);
in
t
t
;
private
ValueType
(
int
type
)
{
t
=
type
;
}
shor
t
t
;
private
ValueType
(
int
type
)
{
t
=
(
short
)
type
;
}
public
static
ValueType
valueOf
(
int
value
,
int
position
)
{
int
temp
=
value
>>
(
position
*
2
);
...
...
@@ -24,5 +24,5 @@ public enum ValueType {
}
return
D
;
}
public
in
t
getValue
()
{
return
t
;
}
public
shor
t
getValue
()
{
return
t
;
}
}
test.kasm
View file @
78af4d1
...
...
@@ -2,9 +2,9 @@ movs $0 r2
add r0 16
add r2 1
movs $0 r2
jdl r0 512 2a,16
jdl r0 512 2
0,16+
a,16
deva 0
deva 1
gpc
gpc %300,16
gpc %
100,16+
300,16
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment