├── cmd ├── bbin │ ├── assets │ │ ├── run.json │ │ ├── run.bbin │ │ └── run.bbasm │ └── main.go └── bb │ ├── main.go │ └── cmd │ ├── run.go │ ├── compile.go │ └── root.go ├── doc ├── image │ └── bbvm-monopoly-demo.png └── bbvm.txt ├── jbbvm ├── gradle.properties ├── bbvm-core │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── me │ │ │ │ └── wener │ │ │ │ └── bbvm │ │ │ │ ├── util │ │ │ │ ├── IsInt.java │ │ │ │ ├── IntEnums.java │ │ │ │ └── Dumper.java │ │ │ │ ├── BeBasicRepl.java │ │ │ │ ├── dev │ │ │ │ ├── package-info.java │ │ │ │ ├── Drawable.java │ │ │ │ ├── swing │ │ │ │ │ ├── package-info.java │ │ │ │ │ ├── SwingContext.java │ │ │ │ │ ├── ImagePanel.java │ │ │ │ │ ├── Draw.java │ │ │ │ │ ├── Swings.java │ │ │ │ │ ├── KeyStateTracker.java │ │ │ │ │ ├── SwingImage.java │ │ │ │ │ ├── SwingModule.java │ │ │ │ │ ├── SwingContextImpl.java │ │ │ │ │ ├── MainFrame.java │ │ │ │ │ ├── StringDrawer.java │ │ │ │ │ ├── SwingImageManager.java │ │ │ │ │ └── SwingPageManager.java │ │ │ │ ├── StringResource.java │ │ │ │ ├── FileManager.java │ │ │ │ ├── ImageResource.java │ │ │ │ ├── Resource.java │ │ │ │ ├── Wrapper.java │ │ │ │ ├── DeviceContext.java │ │ │ │ ├── PageManager.java │ │ │ │ ├── StringManager.java │ │ │ │ ├── ImageManager.java │ │ │ │ ├── InputManager.java │ │ │ │ ├── ResourceManager.java │ │ │ │ ├── FileResource.java │ │ │ │ ├── PageResource.java │ │ │ │ ├── AbstractFileManager.java │ │ │ │ ├── DeviceConstants.java │ │ │ │ └── DefaultStringManager.java │ │ │ │ ├── asm │ │ │ │ ├── BaseNode.java │ │ │ │ ├── AbstractAssembly.java │ │ │ │ ├── Assembly.java │ │ │ │ ├── Inst.java │ │ │ │ ├── Comment.java │ │ │ │ ├── PseudoData.java │ │ │ │ ├── PseudoBlock.java │ │ │ │ ├── Node.java │ │ │ │ ├── Label.java │ │ │ │ ├── SimpleNode.java │ │ │ │ └── BaseBBAsmParser.java │ │ │ │ ├── BeBasicVirtualMachine.java │ │ │ │ ├── vm │ │ │ │ ├── Register.java │ │ │ │ ├── Symbol.java │ │ │ │ ├── event │ │ │ │ │ ├── ResetEvent.java │ │ │ │ │ └── VmTestEvent.java │ │ │ │ ├── SymbolTable.java │ │ │ │ ├── CalculateType.java │ │ │ │ ├── SystemInvokes.java │ │ │ │ ├── DataType.java │ │ │ │ ├── RegisterType.java │ │ │ │ ├── SystemInvoke.java │ │ │ │ ├── package-info.java │ │ │ │ ├── SystemInvokeManager.java │ │ │ │ ├── AddressingMode.java │ │ │ │ ├── CompareType.java │ │ │ │ ├── invoke │ │ │ │ │ ├── InputInvoke.java │ │ │ │ │ ├── OutputInvoke.java │ │ │ │ │ ├── KeyInvoke.java │ │ │ │ │ └── FileInvoke.java │ │ │ │ ├── Value.java │ │ │ │ ├── Symbols.java │ │ │ │ ├── Opcode.java │ │ │ │ ├── Memory.java │ │ │ │ ├── VirtualMachineModule.java │ │ │ │ ├── Operand.java │ │ │ │ └── VMConfig.java │ │ │ │ └── exception │ │ │ │ ├── ExecutionException.java │ │ │ │ └── ResourceMissingException.java │ │ └── test │ │ │ ├── resources │ │ │ └── log4j.properties │ │ │ └── java │ │ │ └── me │ │ │ └── wener │ │ │ └── bbvm │ │ │ ├── vm │ │ │ ├── VMTest.java │ │ │ ├── Dumps.java │ │ │ └── TestSpec.java │ │ │ ├── dev │ │ │ └── swing │ │ │ │ └── ImagesTest.java │ │ │ ├── TestUtil.java │ │ │ └── BasmSpecTest.java │ └── build.gradle ├── bbvm-swing │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── me │ │ │ │ └── wener │ │ │ │ └── bbvm │ │ │ │ └── dev │ │ │ │ └── swing │ │ │ │ └── SwingDev.java │ │ └── test │ │ │ └── java │ │ │ └── me │ │ │ └── wener │ │ │ └── bbvm │ │ │ └── dev │ │ │ └── swing │ │ │ └── SwingDevTest.java │ └── build.gradle ├── settings.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── build.gradle ├── gradlew.bat └── gradlew ├── examples └── hello.bbasm ├── .travis.yml ├── bbasm ├── parser │ ├── parser_test.go │ ├── table_test.go │ ├── util.go │ ├── util_test.go │ ├── testdata │ │ └── exp.txt │ ├── parse_test.go │ ├── table.go │ ├── asm.go │ ├── pseudo_data.go │ ├── parser.go │ ├── build.go │ ├── bbasm_test.go │ ├── ast.go │ └── bbasm.go ├── rt.go ├── exec.go ├── operand.go ├── inst.go └── types.go ├── .editorconfig ├── bbvm ├── std_test.go ├── std_codec.go ├── bbrun │ └── run.go ├── std_io.go ├── std_base.go ├── std_str.go └── instance.go ├── go.mod ├── bbvmjs ├── .editorconfig └── const.js ├── README.md └── .gitignore /cmd/bbin/assets/run.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hello BBvm !" 3 | } 4 | -------------------------------------------------------------------------------- /cmd/bbin/assets/run.bbin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenerme/bbvm/HEAD/cmd/bbin/assets/run.bbin -------------------------------------------------------------------------------- /doc/image/bbvm-monopoly-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenerme/bbvm/HEAD/doc/image/bbvm-monopoly-demo.png -------------------------------------------------------------------------------- /jbbvm/gradle.properties: -------------------------------------------------------------------------------- 1 | projectGroup=me.wener.bbvm 2 | projectName=bbvm 3 | projectVersion=1.0.0-SNAPSHOT 4 | -------------------------------------------------------------------------------- /cmd/bb/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/wenerme/bbvm/cmd/bb/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/util/IsInt.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.util; 2 | 3 | public interface IsInt { 4 | int asInt(); 5 | } 6 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/BeBasicRepl.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/11 6 | */ 7 | public class BeBasicRepl { 8 | } 9 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Device related implementation 3 | * 4 | * @author wener 5 | * @since 15/12/26 6 | */ 7 | package me.wener.bbvm.dev; 8 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/BaseNode.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.asm; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/10 6 | */ 7 | public class BaseNode { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /jbbvm/bbvm-swing/src/main/java/me/wener/bbvm/dev/swing/SwingDev.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/30 6 | */ 7 | public class SwingDev { 8 | } 9 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/BeBasicVirtualMachine.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/10 6 | */ 7 | public class BeBasicVirtualMachine { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/Drawable.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/18 6 | */ 7 | public interface Drawable extends Wrapper { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /jbbvm/bbvm-swing/src/test/java/me/wener/bbvm/dev/swing/SwingDevTest.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/30 6 | */ 7 | public class SwingDevTest { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Device implement based on swing graph, input event, java file. 3 | * 4 | * @author wener 5 | * @since 15/12/29 6 | */ 7 | package me.wener.bbvm.dev.swing; 8 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Register.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/10 6 | */ 7 | public interface Register extends Value { 8 | RegisterType getType(); 9 | } 10 | -------------------------------------------------------------------------------- /jbbvm/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = projectName 2 | 3 | include 'bbvm-core', 'bbvm-swing', 'bbvm-cli' 4 | 5 | //project(':bbvm-core').projectDir = "$rootDir/bbvm-core" as File 6 | //project(':bbvm-swing').projectDir = "$rootDir/bbvm-swing" as File 7 | 8 | -------------------------------------------------------------------------------- /jbbvm/bbvm-swing/build.gradle: -------------------------------------------------------------------------------- 1 | description = '' 2 | dependencies { 3 | compile project(':bbvm-core') 4 | compile group: 'junit', name: 'junit', version: '4.12' 5 | // compile group: 'com.googlecode.lanterna', name: 'lanterna', version:'3.0.0-alpha6' 6 | } 7 | 8 | -------------------------------------------------------------------------------- /jbbvm/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 31 00:07:55 CST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip 7 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Symbol.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | /** 4 | * A symbol represent a address in memory 5 | * 6 | * @author wener 7 | * @since 15/12/11 8 | */ 9 | public interface Symbol { 10 | String getName(); 11 | 12 | int getValue(); 13 | } 14 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/StringResource.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/13 6 | */ 7 | public interface StringResource extends Resource { 8 | String getValue(); 9 | 10 | StringResource setValue(String v); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /examples/hello.bbasm: -------------------------------------------------------------------------------- 1 | ; ____________________ 2 | ; \______ \______ \___ _______ 3 | ; | | _/| | _/\ \/ / \ 4 | ; | | \| | \ \ / Y Y \ 5 | ; |______ /|______ / \_/|__|_| / 6 | ; \/ \/ \/ 7 | 8 | JMP CODE 9 | DATA STR CHAR "Hello, BBvm",0 10 | CODE: 11 | 12 | OUT 1, STR 13 | EXIT 14 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/FileManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/17 6 | */ 7 | public interface FileManager extends ResourceManager { 8 | @Override 9 | default String getType() { 10 | return "file"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingContext.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import me.wener.bbvm.dev.DeviceContext; 4 | 5 | import javax.swing.*; 6 | 7 | /** 8 | * @author wener 9 | * @since 15/12/26 10 | */ 11 | public interface SwingContext extends DeviceContext { 12 | JFrame getFrame(); 13 | } 14 | -------------------------------------------------------------------------------- /cmd/bbin/assets/run.bbasm: -------------------------------------------------------------------------------- 1 | ; ____________________ 2 | ; \______ \______ \___ _______ 3 | ; | | _/| | _/\ \/ / \ 4 | ; | | \| | \ \ / Y Y \ 5 | ; |______ /|______ / \_/|__|_| / 6 | ; \/ \/ \/ 7 | 8 | JMP CODE 9 | DATA STR CHAR "Hello, BBvm",0 10 | CODE: 11 | 12 | OUT 1, STR 13 | EXIT 14 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/ImageResource.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/18 6 | */ 7 | public interface ImageResource extends Resource, Drawable { 8 | @Override 9 | ImageManager getManager(); 10 | 11 | int getWidth(); 12 | 13 | int getHeight(); 14 | } 15 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug,stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 4 | #log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} %m%n 5 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} %5p [%t] (%F:%L) -%m%n 6 | 7 | 8 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/event/ResetEvent.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm.event; 2 | 3 | import me.wener.bbvm.vm.VM; 4 | 5 | import java.util.EventObject; 6 | 7 | /** 8 | * @author wener 9 | * @since 15/12/18 10 | */ 11 | public class ResetEvent extends EventObject { 12 | public ResetEvent(VM source) { 13 | super(source); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/event/VmTestEvent.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm.event; 2 | 3 | import me.wener.bbvm.vm.VM; 4 | 5 | import java.util.EventObject; 6 | 7 | /** 8 | * @author wener 9 | * @since 15/12/18 10 | */ 11 | public class VmTestEvent extends EventObject { 12 | public VmTestEvent(VM source) { 13 | super(source); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/Resource.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/13 6 | */ 7 | public interface Resource extends AutoCloseable, Wrapper { 8 | int getHandler(); 9 | 10 | ResourceManager getManager(); 11 | 12 | /** 13 | * Destroy this resource 14 | */ 15 | @Override 16 | void close(); 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | os: 7 | - linux 8 | 9 | before_install: 10 | - "export DISPLAY=:99.0" 11 | - "sh -e /etc/init.d/xvfb start" 12 | - cd jbbvm 13 | - git clone --depth=1 https://github.com/wenerme/bbvm-test.git 14 | after_success: 15 | - ./gradlew test jacocoTestReport coveralls 16 | # - mvn clean test jacoco:report coveralls:report -DrepoToken=$REPO_TOKEN 17 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/Wrapper.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/18 6 | */ 7 | public interface Wrapper { 8 | @SuppressWarnings("unchecked") 9 | default T unwrap(Class iface) { 10 | return (T) this; 11 | } 12 | 13 | default boolean isWrapperFor(java.lang.Class iface) { 14 | return iface.isAssignableFrom(this.getClass()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/SymbolTable.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import java.util.Map; 4 | import java.util.NavigableMap; 5 | 6 | /** 7 | * @author wener 8 | * @since 15/12/11 9 | */ 10 | public interface SymbolTable { 11 | Symbol getSymbol(String name); 12 | 13 | Symbol getSymbol(int address); 14 | 15 | Map getNameMap(); 16 | 17 | NavigableMap getAddressMap(); 18 | } 19 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/DeviceContext.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * Represent a runtime context 5 | * 6 | * @author wener 7 | * @since 15/12/26 8 | */ 9 | public interface DeviceContext { 10 | PageManager getPageManager(); 11 | 12 | ImageManager getImageManager(); 13 | 14 | InputManager getInputManager(); 15 | 16 | FileManager getFileManager(); 17 | 18 | StringManager getStringManager(); 19 | } 20 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/PageManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/18 6 | */ 7 | public interface PageManager extends ResourceManager { 8 | 9 | PageResource getScreen(); 10 | 11 | int getWidth(); 12 | 13 | int getHeight(); 14 | 15 | PageManager setSize(int w, int h); 16 | 17 | @Override 18 | default String getType() { 19 | return "page"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/StringManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | import com.google.inject.ImplementedBy; 4 | 5 | /** 6 | * Standard string resource implementation 7 | * 8 | * @author wener 9 | * @since 15/12/13 10 | */ 11 | @ImplementedBy(DefaultStringManager.class) 12 | public interface StringManager extends ResourceManager { 13 | 14 | @Override 15 | default String getType() { 16 | return "string"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/CalculateType.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import me.wener.bbvm.util.IsInt; 4 | 5 | /** 6 | * 算数操作符 7 | */ 8 | public enum CalculateType implements IsInt { 9 | ADD(0x0), 10 | SUB(0x1), 11 | MUL(0x2), 12 | DIV(0x3), 13 | MOD(0x4); 14 | 15 | private final int value; 16 | 17 | CalculateType(int value) { 18 | this.value = value; 19 | } 20 | 21 | public int asInt() { 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bbasm/parser/parser_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/davecgh/go-spew/spew" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestResolve(t *testing.T) { 10 | asm := ` 11 | JMP CODE 12 | DATA STR CHAR "Hello, BBvm",0 13 | CODE: 14 | 15 | OUT 1, STR 16 | EXIT 17 | ` 18 | lines, err := Parse(asm) 19 | assert.NoError(t, err) 20 | a := &Assembler{Lines: lines} 21 | _, err = a.Assemble() 22 | assert.NoError(t, err) 23 | spew.Dump(a.Labels) 24 | spew.Dump(a.Symbols) 25 | } 26 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/vm/VMTest.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import me.wener.bbvm.vm.invoke.BasicInvoke; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @author wener 8 | * @since 15/12/11 9 | */ 10 | public class VMTest { 11 | 12 | @Test 13 | public void testLoad() throws Exception { 14 | VM vm = VMConfig.newBuilder().invokeWithSystemOutput().invokeWith(BasicInvoke.class).create(); 15 | vm.setMemory(Memory.load(Dumps.simpleInst().skipBytes(16))).run(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/SystemInvokes.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.Target; 6 | 7 | import static java.lang.annotation.ElementType.METHOD; 8 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 9 | 10 | /** 11 | * @author wener 12 | * @since 15/12/13 13 | */ 14 | @Documented 15 | @Target(METHOD) 16 | @Retention(RUNTIME) 17 | public @interface SystemInvokes { 18 | SystemInvoke[] value(); 19 | } 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = tab 9 | 10 | [**.java] 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [**.groovy] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | [**.gradle] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [**.g4] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | 27 | [**.go] 28 | indent_style = tab 29 | indent_size = 2 30 | 31 | [**.md] 32 | indent_style = space 33 | indent_size = 2 34 | -------------------------------------------------------------------------------- /jbbvm/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | apply plugin: 'maven' 3 | 4 | group = projectGroup 5 | version = projectVersion 6 | } 7 | 8 | subprojects { 9 | apply plugin: 'java' 10 | sourceCompatibility = 1.8 11 | targetCompatibility = 1.8 12 | 13 | repositories { 14 | mavenLocal() 15 | // maven { url "http://repo.maven.apache.org/maven2" } 16 | mavenCentral() 17 | jcenter() 18 | } 19 | 20 | dependencies { 21 | compile 'org.slf4j:slf4j-api:1.7.13' 22 | testCompile 'junit:junit:4.12' 23 | } 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /bbasm/parser/table_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "github.com/wenerme/bbvm/bbasm" 6 | "testing" 7 | ) 8 | 9 | func TestLookup(t *testing.T) { 10 | tests := []struct { 11 | t interface{} 12 | v string 13 | exp interface{} 14 | }{ 15 | {bbasm.INT, "Int", bbasm.INT}, 16 | {bbasm.INT, "int", bbasm.INT}, 17 | {bbasm.INT, "word", bbasm.WORD}, 18 | {bbasm.R0, "rP", bbasm.RP}, 19 | {bbasm.R0, "rxz", nil}, 20 | } 21 | for _, test := range tests { 22 | assert.Equal(t, test.exp, Lookup(test.t, test.v)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bbvm/std_test.go: -------------------------------------------------------------------------------- 1 | package bbvm 2 | 3 | import ( 4 | "context" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestStdUse(t *testing.T) { 10 | a := &Std{ 11 | PrintInt: func(ctx context.Context, v int) { 12 | t.Fail() 13 | }, 14 | PrintChar: func(ctx context.Context, v int) { 15 | 16 | }, 17 | } 18 | b := &Std{ 19 | PrintInt: func(ctx context.Context, v int) { 20 | }, 21 | VmTest: func(ctx context.Context) { 22 | }, 23 | } 24 | a.Use(b) 25 | assert.NotNil(t, a.VmTest) 26 | assert.NotNil(t, a.PrintChar) 27 | a.PrintInt(nil, 0) 28 | } 29 | -------------------------------------------------------------------------------- /cmd/bbin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | "flag" 6 | "github.com/wenerme/bbvm/bbvm/bbrun" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | //go:embed assets/run.bbin 11 | var bin []byte 12 | 13 | //go:embed assets/run.json 14 | var info string 15 | 16 | func main() { 17 | debug := flag.Bool("D", false, "Debug") 18 | 19 | flag.Parse() 20 | 21 | if *debug { 22 | logger, _ := zap.NewDevelopmentConfig().Build() 23 | zap.ReplaceGlobals(logger) 24 | } 25 | 26 | err := bbrun.Run(info, bin) 27 | if err != nil { 28 | zap.S().With("err", err).Fatal("run failed") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bbasm/rt.go: -------------------------------------------------------------------------------- 1 | package bbasm 2 | 3 | import "context" 4 | 5 | type Runtime interface { 6 | Memory 7 | 8 | Push(val int) // push stack 9 | Pop() int // pop stack 10 | Register(typ RegisterType) Register 11 | Jump(addr int) 12 | Exit() 13 | In(ctx context.Context, a int, b int) 14 | Out(ctx context.Context, a int, b int) 15 | } 16 | 17 | type Register interface { 18 | Get() int 19 | Set(int) 20 | Float() float32 21 | SetFloat(v float32) 22 | } 23 | 24 | type Memory interface { 25 | GetInt(int) int 26 | SetInt(int, int) 27 | GetFloat(int) float32 28 | SetFloat(int, float32) 29 | GetString(int) string 30 | } 31 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/DataType.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import me.wener.bbvm.util.IsInt; 4 | 5 | /** 6 | * 数据类型
 7 |  * DWORD  | 0x0
 8 |  * WORD   | 0x1
 9 |  * BYTE   | 0x2
10 |  * FLOAT  | 0x3
11 |  * INT    | 0x4
12 |  * 
13 | */ 14 | public enum DataType implements IsInt { 15 | DWORD(0x0), 16 | WORD(0x1), 17 | BYTE(0x2), 18 | FLOAT(0x3), 19 | INT(0x4); 20 | 21 | private final int value; 22 | 23 | DataType(int value) { 24 | this.value = value; 25 | } 26 | 27 | public int asInt() { 28 | return value; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/ImageManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author wener 7 | * @since 15/12/18 8 | */ 9 | public interface ImageManager extends ResourceManager { 10 | /** 11 | * @param file Resource name 12 | * @param index Resource index start from 0 13 | */ 14 | ImageResource load(String file, int index); 15 | 16 | /** 17 | * @return Mutable directories to search the resource 18 | */ 19 | List getResourceDirectory(); 20 | 21 | @Override 22 | default String getType() { 23 | return "image"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bbasm/parser/util.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/juju/errors" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func trim(s string) string { 10 | return strings.Trim(s, " \t\r") 11 | } 12 | func parseInt(s string) (ret int32, e error) { 13 | val := trim(s) 14 | var i int64 15 | if len(val) > 2 && val[0] == '0' { 16 | switch val[0:2] { 17 | case "0x", "0X": 18 | i, e = strconv.ParseInt(val[2:], 16, 32) 19 | case "0b", "0B": 20 | i, e = strconv.ParseInt(val[2:], 2, 32) 21 | default: 22 | i, e = strconv.ParseInt(val[1:], 8, 32) 23 | } 24 | } else { 25 | i, e = strconv.ParseInt(val, 10, 32) 26 | } 27 | 28 | if e != nil { 29 | e = errors.Trace(e) 30 | } 31 | 32 | ret = int32(i) 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /bbasm/parser/util_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "math" 6 | "testing" 7 | ) 8 | 9 | func TestParseInt(t *testing.T) { 10 | ERR := int32(math.MaxInt32 - 2) 11 | tests := []struct { 12 | Val string 13 | I int32 14 | }{ 15 | {"10", 10}, 16 | {"0x10", 16}, 17 | {"0X10", 16}, 18 | {"0b10", 2}, 19 | {"0B10", 2}, 20 | {"010", 8}, 21 | 22 | {"1A", ERR}, 23 | {"0x1G", ERR}, 24 | {"0y10", ERR}, 25 | {"0b102", ERR}, 26 | {"0B1a0", ERR}, 27 | {"019", ERR}, 28 | } 29 | 30 | for _, v := range tests { 31 | i, e := parseInt(v.Val) 32 | if v.I == ERR { 33 | assert.Error(t, e) 34 | } else { 35 | assert.NoError(t, e) 36 | assert.EqualValues(t, v.I, i) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/RegisterType.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import me.wener.bbvm.util.IsInt; 4 | 5 | /** 6 | * 寄存器类型 7 | *
 8 |  * RP | 0x0 | 程序计数器
 9 |  * RF | 0x1 | 比较标示符
10 |  * RS | 0x2 | 栈顶位置
11 |  * RB | 0x3 | 栈底位置
12 |  * R0 | 0x4 | #0 寄存器
13 |  * R1 | 0x5 | #1 寄存器
14 |  * R2 | 0x6 | #2 寄存器
15 |  * R3 | 0x7 | #3 寄存器
16 |  * 
17 | */ 18 | public enum RegisterType implements IsInt { 19 | RP(0x0), 20 | RF(0x1), 21 | RS(0x2), 22 | RB(0x3), 23 | R0(0x4), 24 | R1(0x5), 25 | R2(0x6), 26 | R3(0x7); 27 | 28 | private final int value; 29 | 30 | RegisterType(int value) { 31 | this.value = value; 32 | } 33 | 34 | public int asInt() { 35 | return value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/ImagePanel.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * The container for the image 9 | * 10 | * @author wener 11 | * @since 15/12/28 12 | */ 13 | class ImagePanel extends JPanel { 14 | private final Supplier image; 15 | 16 | public ImagePanel(Supplier image) { 17 | super(true); 18 | this.image = image; 19 | } 20 | 21 | @Override 22 | protected void paintComponent(Graphics g) { 23 | super.paintComponent(g); 24 | 25 | g.drawImage(image.get(), 0, 0, null); 26 | } 27 | 28 | public void refresh() { 29 | repaint(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bbasm/parser/testdata/exp.txt: -------------------------------------------------------------------------------- 1 | ; wener 2 | ; ok 3 | Ld int a, [b] ; This is my comment 4 | 5 | exit 6 | ret 7 | nop 8 | 9 | push [100] 10 | pop [r1] 11 | jmp b 12 | call 1 13 | 14 | cal dword mul r0, 10 15 | cal word add [r0], [ r1 ] ; Test spacing 16 | cal word add 11 , [ 12 ] 17 | 18 | in 10, r0 19 | out [0],BALABALA 20 | 21 | LAB : 22 | 23 | JPC A XY 24 | JPC NZ YH 25 | 26 | LAC: ; This the comment on label 27 | 28 | .BLOCK 10 20 29 | 30 | INT: 31 | 32 | LD INT r1,INT 33 | CAL INT ADD [ADD],r0 34 | 35 | .BLOCK 10 -20 ; Comment on block 36 | lD byte r1, -10001 37 | 38 | DATA X INT 1001 ; Optional Date type 39 | DATA Y 1002, 1003 40 | DATA Z "Good c\"har",0 41 | 42 | jpc AE 10 43 | Jpc A [10] 44 | Jpc BE [ r1 ] 45 | 46 | DATA LAB CHAR %00ABcdEf% ; Support hex data format 47 | -------------------------------------------------------------------------------- /bbvm/std_codec.go: -------------------------------------------------------------------------------- 1 | package bbvm 2 | 3 | import ( 4 | "github.com/wenerme/bbvm/bbasm" 5 | "golang.org/x/text/encoding/simplifiedchinese" 6 | ) 7 | 8 | func StdUTF8(rt bbasm.Runtime, std *Std) *Std { 9 | return &Std{ 10 | BytesToString: func(b []byte) (string, error) { 11 | return string(b), nil 12 | }, 13 | StringToBytes: func(s string) ([]byte, error) { 14 | return []byte(s), nil 15 | }, 16 | } 17 | } 18 | func StdGBK(rt bbasm.Runtime, std *Std) *Std { 19 | return &Std{ 20 | BytesToString: func(b []byte) (string, error) { 21 | bytes, err := simplifiedchinese.GBK.NewDecoder().Bytes(b) 22 | return string(bytes), err 23 | }, 24 | StringToBytes: func(s string) ([]byte, error) { 25 | return simplifiedchinese.GBK.NewEncoder().Bytes([]byte(s)) 26 | }, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/SystemInvoke.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Repeatable; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import static java.lang.annotation.ElementType.METHOD; 9 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 10 | 11 | /** 12 | * @author wener 13 | * @since 15/12/13 14 | */ 15 | @Documented 16 | @Target(METHOD) 17 | @Retention(RUNTIME) 18 | @Repeatable(SystemInvokes.class) 19 | public @interface SystemInvoke { 20 | int ANY = Integer.MIN_VALUE; 21 | 22 | Type type(); 23 | 24 | int a() default ANY; 25 | 26 | int b() default ANY; 27 | 28 | enum Type { 29 | IN, OUT 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bbvm/bbrun/run.go: -------------------------------------------------------------------------------- 1 | package bbrun 2 | 3 | import ( 4 | "context" 5 | "github.com/wenerme/bbvm/bbvm" 6 | "go.uber.org/zap" 7 | "os" 8 | "reflect" 9 | ) 10 | 11 | func Run(name string, rom []byte) error { 12 | vm := bbvm.NewInstance() 13 | vm.Std = &bbvm.Std{} 14 | vm.Std.Use(bbvm.StdBase(vm, vm.Std)) 15 | vm.Std.Use(bbvm.StdGBK(vm, vm.Std)) 16 | vm.Std.Use(bbvm.StdStringRes(vm, vm.Std)) 17 | vm.Std.Use(bbvm.StdStringFunc(vm, vm.Std)) 18 | vm.Std.Use(bbvm.NewPrintToWriter(os.Stdout)(vm, vm.Std)) 19 | // report missing std 20 | rv := reflect.ValueOf(vm.Std).Elem() 21 | rt := rv.Type() 22 | n := rv.NumField() 23 | for i := 0; i < n; i++ { 24 | f := rv.Field(i) 25 | if f.IsNil() { 26 | zap.S().With("std", rt.Field(i).Name).Debug("missing std") 27 | } 28 | } 29 | vm.Load(rom) 30 | return vm.Run(context.Background()) 31 | } 32 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/exception/ExecutionException.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.exception; 2 | 3 | import me.wener.bbvm.vm.VM; 4 | 5 | /** 6 | * @author wener 7 | * @since 15/12/13 8 | */ 9 | public class ExecutionException extends RuntimeException { 10 | private VM vm; 11 | 12 | public ExecutionException() { 13 | } 14 | 15 | public ExecutionException(String message) { 16 | super(message); 17 | } 18 | 19 | public ExecutionException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | public ExecutionException(Throwable cause) { 24 | super(cause); 25 | } 26 | 27 | public VM getVm() { 28 | return vm; 29 | } 30 | 31 | public ExecutionException setVm(VM vm) { 32 | this.vm = vm; 33 | return this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/AbstractAssembly.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.asm; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * @author wener 7 | * @since 15/12/11 8 | */ 9 | abstract class AbstractAssembly implements Assembly { 10 | Comment comment; 11 | 12 | public Comment getComment() { 13 | return comment; 14 | } 15 | 16 | public void setComment(Comment comment) { 17 | this.comment = comment; 18 | } 19 | 20 | protected String commentAssembly() { 21 | return comment != null ? " " + comment.toAssembly() : ""; 22 | } 23 | 24 | public boolean hasComment() { 25 | return comment != null; 26 | } 27 | 28 | @Override 29 | public void write(ByteBuf buf) { 30 | 31 | } 32 | 33 | @Override 34 | public int length() { 35 | return 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/Draw.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import me.wener.bbvm.dev.Drawable; 4 | 5 | import java.awt.*; 6 | import java.awt.image.BufferedImage; 7 | 8 | /** 9 | * @author wener 10 | * @since 15/12/26 11 | */ 12 | class Draw implements Drawable { 13 | protected final BufferedImage image; 14 | protected final Graphics2D g; 15 | 16 | Draw(BufferedImage image) { 17 | this.image = image; 18 | g = image.createGraphics(); 19 | // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 20 | } 21 | 22 | public int getWidth() { 23 | return image.getWidth(); 24 | } 25 | 26 | public int getHeight() { 27 | return image.getHeight(); 28 | } 29 | 30 | public BufferedImage getImage() { 31 | return image; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/InputManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/19 6 | */ 7 | public interface InputManager { 8 | 9 | boolean isKeyPressed(int key); 10 | 11 | /** 12 | * @return Wait any key or mouse click. 13 | */ 14 | int waitKey(); 15 | 16 | /** 17 | * Test is there any key press or mouse click. 18 | */ 19 | int inKey(); 20 | 21 | String inKeyString(); 22 | 23 | /** 24 | * @return read a string, use Enter of confirm. 25 | */ 26 | String readText(); 27 | 28 | default int makeClickKey(int x, int y) { 29 | return x | 0x80000000 | (y << 16); 30 | } 31 | 32 | default int getX(int key) { 33 | return key & 0xFFFF; 34 | } 35 | 36 | default int getY(int key) { 37 | return key >>> 16 ^ 0x8000; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/Assembly.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.asm; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * @author wener 7 | * @since 15/12/11 8 | */ 9 | public interface Assembly { 10 | /** 11 | * If this assembly interests parser 12 | */ 13 | default void setParser(BBAsmParser parser) { 14 | } 15 | 16 | Type getType(); 17 | 18 | String toAssembly(); 19 | 20 | /** 21 | * @return {@link Comment} for this {@link Assembly} or {@code null} 22 | */ 23 | Comment getComment(); 24 | 25 | void setComment(Comment comment); 26 | 27 | boolean hasComment(); 28 | 29 | /** 30 | * @return The length of this assembly 31 | */ 32 | int length(); 33 | 34 | void write(ByteBuf buf); 35 | 36 | int getLine(); 37 | 38 | enum Type { 39 | LABEL, COMMENT, PSEUDO, INST 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/Swings.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import com.google.inject.Module; 4 | import me.wener.bbvm.dev.DeviceConstants; 5 | import me.wener.bbvm.dev.ResourceManager; 6 | import me.wener.bbvm.exception.ResourceMissingException; 7 | import me.wener.bbvm.util.IntEnums; 8 | 9 | /** 10 | * @author wener 11 | * @since 15/12/18 12 | */ 13 | public class Swings implements DeviceConstants { 14 | static { 15 | IntEnums.cache(FontType.class); 16 | } 17 | 18 | public static Module module() { 19 | return new SwingModule(); 20 | } 21 | 22 | static T checkMissing(ResourceManager mgr, int handler, T v) { 23 | if (v == null) { 24 | throw new ResourceMissingException(String.format("%s #%s not exists", mgr.getType(), handler), handler); 25 | } 26 | return v; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wenerme/bbvm 2 | 3 | go 1.16 4 | 5 | require ( 6 | fyne.io/fyne/v2 v2.0.3 7 | github.com/davecgh/go-spew v1.1.1 8 | github.com/juju/errors v0.0.0-20200330140219-3fe23663418f 9 | github.com/juju/testing v0.0.0-20210324180055-18c50b0c2098 // indirect 10 | github.com/mitchellh/go-homedir v1.1.0 11 | github.com/ngaut/log v0.0.0-20180314031856-b8e36e7ba5ac 12 | github.com/pkg/errors v0.9.1 13 | github.com/spacemonkeygo/errors v0.0.0-20201030155909-2f5f890dbc62 14 | github.com/spf13/cobra v1.1.3 15 | github.com/spf13/viper v1.8.0 16 | github.com/sqweek/dialog v0.0.0-20200911184034-8a3d98e8211d // indirect 17 | github.com/stretchr/testify v1.7.0 18 | go.uber.org/atomic v1.8.0 // indirect 19 | go.uber.org/multierr v1.7.0 // indirect 20 | go.uber.org/zap v1.17.0 // indirect 21 | golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c // indirect 22 | golang.org/x/text v0.3.6 23 | ) 24 | -------------------------------------------------------------------------------- /bbvmjs/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{js,py}] 14 | charset = utf-8 15 | 16 | # 4 space indentation 17 | [*.py] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # 2 space indentation 22 | [*.pegjs] 23 | indent_style = space 24 | indent_size = 2 25 | 26 | # Tab indentation (no size specified) 27 | [Makefile] 28 | indent_style = tab 29 | 30 | # Indentation override for all JS under lib directory 31 | [lib/**.js] 32 | indent_style = space 33 | indent_size = 2 34 | 35 | # Matches the exact files either package.json or .travis.yml 36 | [{package.json,.travis.yml}] 37 | indent_style = space 38 | indent_size = 2 39 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/exception/ResourceMissingException.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.exception; 2 | 3 | import com.google.common.base.MoreObjects; 4 | 5 | /** 6 | * @author wener 7 | * @since 15/12/13 8 | */ 9 | public class ResourceMissingException extends ExecutionException { 10 | private String type; 11 | private int handler; 12 | 13 | public ResourceMissingException(String message, String type, int handler) { 14 | super(message); 15 | this.type = type; 16 | this.handler = handler; 17 | } 18 | 19 | public ResourceMissingException(String type, int handler) { 20 | this.type = type; 21 | this.handler = handler; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return MoreObjects.toStringHelper(this) 27 | .add("type", type) 28 | .add("handler", handler) 29 | .add("message", getMessage()) 30 | .toString(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/package-info.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | /** 3 | * BB 定义的一些常量 4 | *
 5 |  * Const KEY_UP       = 38
 6 |  * Const KEY_DOWN     = 40
 7 |  * Const KEY_LEFT     = 37
 8 |  * Const KEY_RIGHT    = 39
 9 |  * Const KEY_SPACE    = 32
10 |  * Const KEY_ESCAPE   = 27
11 |  * Const KEY_ENTER    = 13
12 |  *
13 |  * Const ENV_SIM = 0
14 |  * Const ENV_9288 = 9288
15 |  * Const ENV_9188 = 9188
16 |  * Const ENV_9288T = 9287	'9288-1
17 |  * Const ENV_9288S = 9286	'9288-2
18 |  * Const ENV_9388 = 9388
19 |  *
20 |  * Const FONT_12SONG = 0
21 |  * Const FONT_12KAI = 1
22 |  * Const FONT_12HEI = 2
23 |  * Const FONT_16SONG = 3
24 |  * Const FONT_16KAI = 4
25 |  * Const FONT_16HEI = 5
26 |  * Const FONT_24SONG = 6
27 |  * Const FONT_24KAI = 7
28 |  * Const FONT_24HEI = 8
29 |  *
30 |  * Const TRANSPARENT = 1
31 |  * Const OPAQUE = 2
32 |  *
33 |  * Const PEN_SOLID =	0
34 |  * Const PEN_DASH	 =	1
35 |  *
36 |  * Const BRUSH_SOLID = 0
37 |  * 
38 |  */
39 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/util/IntEnums.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.util;
 2 | 
 3 | import com.google.common.collect.HashBasedTable;
 4 | import com.google.common.collect.Table;
 5 | 
 6 | /**
 7 |  * @author wener
 8 |  * @since 15/12/10
 9 |  */
10 | public class IntEnums {
11 |     private static final Table cache = HashBasedTable.create();
12 | 
13 |     @SafeVarargs
14 |     public static  void cache(Class... type) {
15 |         for (Class t : type) {
16 |             cache(t);
17 |         }
18 |     }
19 | 
20 |     private static  void cache(Class type) {
21 |         for (T item : type.getEnumConstants()) {
22 |             cache.put(type, item.asInt(), item);
23 |         }
24 |     }
25 | 
26 |     @SuppressWarnings("unchecked")
27 |     public static  T fromInt(Class type, int value) {
28 |         return (T) cache.get(type, value);
29 |     }
30 | }
31 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/SystemInvokeManager.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import com.google.common.base.Function;
 4 | import com.google.inject.ImplementedBy;
 5 | 
 6 | /**
 7 |  * @author wener
 8 |  * @since 15/12/13
 9 |  */
10 | @ImplementedBy(SystemInvokeManagerImpl.class)
11 | public interface SystemInvokeManager {
12 | 
13 |     /**
14 |      * Register all method with annotation {@link SystemInvoke}, if register a class will use {@linkplain com.google.inject.Injector Injector} to create new instance.
15 |      * If there is already have a handler for type,a,b will throw an exception.
16 |      *
17 |      * @param handlers Object or Class
18 |      */
19 |     void register(Object... handlers);
20 | 
21 | //    void register(boolean override,Object... handlers);
22 | 
23 |     void register(SystemInvoke.Type type, int a, int b, Function handler);
24 | 
25 |     Object invoke(Instruction inst);
26 | 
27 |     Function getHandler(SystemInvoke.Type type, int a, int b);
28 | }
29 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/AddressingMode.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import me.wener.bbvm.util.IsInt;
 4 | 
 5 | public enum AddressingMode implements IsInt {
 6 |     /*
 7 |     表示	| 字节码 | 说明
 8 | --------|-----|----
 9 | rx		| 0x0 | 寄存器寻址
10 | [rx]	| 0x1 | 寄存器间接寻址
11 | n		| 0x2 | 立即数寻址
12 | [n]	| 0x3 | 直接寻址
13 | 
14 | op1/op2	|rx		| [rx]	| n	    | [n]
15 | --------|-------|-------|-------|----
16 | rx		| 0x0	| 0x1	| 0x2	| 0x3
17 | [rx]	| 0x4	| 0x5	| 0x6	| 0x7
18 | n		| 0x8	| 0x9	| 0xa	| 0xb
19 | [n]	    | 0xc	| 0xd	| 0xe	| 0xf
20 |      */
21 |     /**
22 |      * 寄存器寻址
23 |      */
24 |     REGISTER(0x0),
25 |     /**
26 |      * 寄存器间接寻址
27 |      */
28 |     REGISTER_DEFERRED(0x1),
29 |     /**
30 |      * 立即数
31 |      */
32 |     IMMEDIATE(0x2),
33 |     /**
34 |      * 直接寻址
35 |      */
36 |     DIRECT(0x3);
37 |     private final int val;
38 | 
39 |     AddressingMode(int val) {
40 |         this.val = val;
41 |     }
42 | 
43 |     @Override
44 |     public int asInt() {
45 |         return val;
46 |     }
47 | 
48 | }
49 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/KeyStateTracker.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.dev.swing;
 2 | 
 3 | import com.google.common.cache.Cache;
 4 | import com.google.common.cache.CacheBuilder;
 5 | 
 6 | import java.awt.event.InputEvent;
 7 | import java.awt.event.KeyEvent;
 8 | import java.util.concurrent.TimeUnit;
 9 | 
10 | /**
11 |  * @author wener
12 |  * @since 15/12/27
13 |  */
14 | class KeyStateTracker {
15 |     private final Cache cache = CacheBuilder
16 |             .newBuilder()
17 |             .expireAfterWrite(100, TimeUnit.MILLISECONDS)
18 |             .build();
19 | 
20 |     public boolean isPressed(int keyCode) {
21 |         return cache.getIfPresent(keyCode) != null;
22 |     }
23 | 
24 |     public KeyStateTracker offer(InputEvent e) {
25 |         switch (e.getID()) {
26 |             case KeyEvent.KEY_PRESSED:
27 |                 cache.put(((KeyEvent) e).getKeyCode(), Boolean.TRUE);
28 |                 break;
29 |             case KeyEvent.KEY_RELEASED:
30 |                 cache.invalidate(((KeyEvent) e).getKeyCode());
31 |                 break;
32 |         }
33 |         return this;
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/ResourceManager.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.dev;
 2 | 
 3 | import com.google.common.base.Throwables;
 4 | import me.wener.bbvm.exception.ResourceMissingException;
 5 | 
 6 | /**
 7 |  * @author wener
 8 |  * @since 15/12/13
 9 |  */
10 | public interface ResourceManager {
11 |     R getResource(int handler) throws ResourceMissingException;
12 | 
13 |     /**
14 |      * Close this resource, if the resource is not exists may not throw an exception
15 |      */
16 |     default R close(int handler) {
17 |         try {
18 |             R resource = getResource(handler);
19 |             resource.close();
20 |         } catch (ResourceMissingException e) {
21 |             // ignored
22 |         } catch (Exception e) {
23 |             Throwables.propagate(e);
24 |         }
25 | 
26 |         return null;
27 |     }
28 | 
29 |     @SuppressWarnings("unchecked")
30 |     default M reset() {
31 |         // If this resources do not need to reset
32 |         return (M) this;
33 |     }
34 | 
35 |     default R create() {
36 |         throw new UnsupportedOperationException();
37 |     }
38 | 
39 |     String getType();
40 | 
41 | }
42 | 


--------------------------------------------------------------------------------
/bbasm/parser/parse_test.go:
--------------------------------------------------------------------------------
 1 | package parser_test
 2 | 
 3 | import (
 4 | 	"encoding"
 5 | 	"encoding/hex"
 6 | 	"github.com/davecgh/go-spew/spew"
 7 | 	"github.com/stretchr/testify/assert"
 8 | 	"github.com/wenerme/bbvm/bbasm/parser"
 9 | 	"log"
10 | 	"testing"
11 | )
12 | 
13 | func TestParseLine(t *testing.T) {
14 | 	for _, test := range []struct {
15 | 		L string
16 | 		S string
17 | 		B []byte
18 | 	}{
19 | 		{
20 | 			L: `DATA STR CHAR "Hello, BBvm",0`,
21 | 			B: []byte("Hello, BBvm\x00\x00\x00\x00"),
22 | 			S: `DATA STR "Hello, BBvm", 0`,
23 | 		},
24 | 	} {
25 | 		assembly, err := parser.ParseLine(test.L + "\n")
26 | 		assert.NoError(t, err)
27 | 		if !assert.NotNil(t, assembly) {
28 | 			continue
29 | 		}
30 | 		bm, isBin := assembly.(encoding.BinaryMarshaler)
31 | 		var bin []byte
32 | 		if isBin {
33 | 			bin, err = bm.MarshalBinary()
34 | 			assert.NoError(t, err)
35 | 		}
36 | 		asm := assembly.Assembly()
37 | 
38 | 		log.Printf("PARSE %v -> %v", test.L, asm)
39 | 		log.Printf("\t  %v", hex.Dump(bin))
40 | 
41 | 		if test.S != "" {
42 | 			assert.Equal(t, test.S, asm)
43 | 		}
44 | 		if test.B != nil {
45 | 			if !assert.Equal(t, test.B, bin) {
46 | 				spew.Dump(assembly)
47 | 			}
48 | 		}
49 | 	}
50 | }
51 | 
52 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/FileResource.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.dev;
 2 | 
 3 | import java.io.IOException;
 4 | 
 5 | /**
 6 |  * @author wener
 7 |  * @since 15/12/17
 8 |  */
 9 | public interface FileResource extends Resource {
10 | 
11 |     @Override
12 |     FileManager getManager();
13 | 
14 |     FileResource open(String string) throws IOException;
15 | 
16 |     default int readInt(int address) throws IOException {
17 |         return seek(address).readInt();
18 |     }
19 | 
20 |     default String readString(int address) throws IOException {
21 |         return seek(address).readString();
22 |     }
23 | 
24 |     int readInt() throws IOException;
25 | 
26 |     String readString() throws IOException;
27 | 
28 |     FileResource writeInt(int address, int v) throws IOException;
29 | 
30 |     FileResource writeString(int address, String v) throws IOException;
31 | 
32 |     FileResource writeInt(int v) throws IOException;
33 | 
34 |     FileResource writeString(String v) throws IOException;
35 | 
36 |     boolean isEof() throws IOException;
37 | 
38 |     int length() throws IOException;
39 | 
40 |     int tell() throws IOException;
41 | 
42 |     FileResource seek(int i) throws IOException;
43 | 
44 |     @Override
45 |     void close();
46 | }
47 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingImage.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.dev.swing;
 2 | 
 3 | import com.google.common.base.MoreObjects;
 4 | import me.wener.bbvm.dev.ImageManager;
 5 | import me.wener.bbvm.dev.ImageResource;
 6 | 
 7 | import java.awt.image.BufferedImage;
 8 | 
 9 | /**
10 |  * @author wener
11 |  * @since 15/12/26
12 |  */
13 | class SwingImage extends Draw implements ImageResource {
14 |     private final int handler;
15 |     private final SwingImageManager manager;
16 |     public String name;
17 | 
18 |     SwingImage(int handler, SwingImageManager manager, BufferedImage image) {
19 |         super(image);
20 |         this.handler = handler;
21 |         this.manager = manager;
22 |     }
23 | 
24 |     @Override
25 |     public int getHandler() {
26 |         return handler;
27 |     }
28 | 
29 |     @Override
30 |     public ImageManager getManager() {
31 |         return manager;
32 |     }
33 | 
34 |     @Override
35 |     public void close() {
36 |         manager.close(this);
37 |     }
38 | 
39 |     @Override
40 |     public String toString() {
41 |         return MoreObjects.toStringHelper(this)
42 |             .add("handler", handler)
43 |             .add("width", getWidth())
44 |             .add("height", getHeight())
45 |             .add("name", name)
46 |             .toString();
47 |     }
48 | }
49 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/Inst.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.asm;
 2 | 
 3 | import io.netty.buffer.ByteBuf;
 4 | import me.wener.bbvm.vm.Instruction;
 5 | 
 6 | /**
 7 |  * @author wener
 8 |  * @since 15/12/11
 9 |  */
10 | public class Inst extends AbstractAssembly implements Assembly {
11 |     private Instruction instruction;
12 |     private int line;
13 | 
14 |     public Inst(Instruction instruction) {
15 |         this.instruction = instruction;
16 |     }
17 | 
18 |     @Override
19 |     public Type getType() {
20 |         return Type.INST;
21 |     }
22 | 
23 |     public Instruction getInstruction() {
24 |         return instruction;
25 |     }
26 | 
27 |     @Override
28 |     public String toAssembly() {
29 |         return instruction.toAssembly() + commentAssembly();
30 |     }
31 | 
32 |     @Override
33 |     public String toString() {
34 |         return instruction.toString();
35 |     }
36 | 
37 |     @Override
38 |     public void write(ByteBuf buf) {
39 |         instruction.write(buf);
40 |     }
41 | 
42 |     @Override
43 |     public int getLine() {
44 |         return line;
45 |     }
46 | 
47 |     public Inst setLine(int line) {
48 |         this.line = line;
49 |         return this;
50 |     }
51 | 
52 |     @Override
53 |     public int length() {
54 |         return instruction.getOpcode().length();
55 |     }
56 | }
57 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/CompareType.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import me.wener.bbvm.util.IsInt;
 4 | 
 5 | /**
 6 |  * Z    | 0x1 | 等于
 7 |  * B    | 0x2 | Below,小于
 8 |  * BE   | 0x3 | 小于等于
 9 |  * A    | 0x4 | Above,大于
10 |  * AE   | 0x5 | 大于等于
11 |  * NZ   | 0x6 | 不等于
12 |  */
13 | public enum CompareType implements IsInt {
14 |     Z(0x1),
15 |     B(0x2),
16 |     BE(0x3),
17 |     A(0x4),
18 |     AE(0x5),
19 |     NZ(0x6);
20 |     private final int value;
21 | 
22 |     CompareType(int value) {
23 |         this.value = value;
24 |     }
25 | 
26 |     public int asInt() {
27 |         return value;
28 |     }
29 | 
30 |     public boolean isMatch(CompareType b) {
31 |         // 比较后的结果只有 大于 等于 小于
32 |         // 需要匹配的包括所有条件
33 |         switch (this) {
34 |             case A:
35 |                 if (b == CompareType.AE || b == CompareType.A || b == CompareType.NZ)
36 |                     return true;
37 |                 break;
38 |             case B:
39 |                 if (b == CompareType.BE || b == CompareType.B || b == CompareType.NZ)
40 |                     return true;
41 |                 break;
42 |             case Z:
43 |                 if (b == CompareType.Z || b == CompareType.AE || b == CompareType.BE)
44 |                     return true;
45 |                 break;
46 |         }
47 |         return this == b;
48 |     }
49 | }
50 | 


--------------------------------------------------------------------------------
/bbasm/parser/table.go:
--------------------------------------------------------------------------------
 1 | package parser
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"github.com/wenerme/bbvm/bbasm"
 6 | 	"reflect"
 7 | 	"strings"
 8 | )
 9 | 
10 | var lookTable = make(map[reflect.Type]map[string]interface{})
11 | 
12 | func init() {
13 | 	for i := bbasm.DWORD; i <= bbasm.INT; i++ {
14 | 		putLookTable(i)
15 | 	}
16 | 	for i := bbasm.Z; i <= bbasm.NZ; i++ {
17 | 		putLookTable(i)
18 | 	}
19 | 	for i := bbasm.ADD; i <= bbasm.MOD; i++ {
20 | 		putLookTable(i)
21 | 	}
22 | 	for i := bbasm.NOP; i <= bbasm.CAL; i++ {
23 | 		putLookTable(i)
24 | 	}
25 | 	putLookTable(bbasm.EXIT)
26 | 
27 | 	for i := bbasm.AddressRegister; i <= bbasm.AddressDirect; i++ {
28 | 		putLookTable(i)
29 | 	}
30 | 	for i := bbasm.RP; i <= bbasm.R3; i++ {
31 | 		putLookTable(i)
32 | 	}
33 | }
34 | 
35 | func putLookTable(v interface{}) {
36 | 	m := lookTable[reflect.TypeOf(v)]
37 | 	if m == nil {
38 | 		m = make(map[string]interface{})
39 | 		lookTable[reflect.TypeOf(v)] = m
40 | 	}
41 | 	m[v.(fmt.Stringer).String()] = v
42 | }
43 | 
44 | // Lookup type t by string v, will upper case v.
45 | //
46 | // Return nil if not found
47 | func Lookup(t interface{}, v string) (ret interface{}) {
48 | 	var lookType reflect.Type
49 | 	if ty, ok := t.(reflect.Type); ok {
50 | 		lookType = ty
51 | 	} else {
52 | 		lookType = reflect.TypeOf(t)
53 | 	}
54 | 	m := lookTable[lookType]
55 | 	if m != nil {
56 | 		ret = m[strings.ToUpper(v)]
57 | 	}
58 | 	return
59 | }
60 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/util/Dumper.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.util;
 2 | 
 3 | import com.google.common.base.Throwables;
 4 | import io.netty.buffer.ByteBuf;
 5 | import org.apache.commons.io.HexDump;
 6 | 
 7 | import java.io.ByteArrayOutputStream;
 8 | import java.io.IOException;
 9 | import java.util.Arrays;
10 | 
11 | /**
12 |  * 与 Stringer 类似,但是会输出更多调试相关的信息
13 |  */
14 | public class Dumper {
15 |     // region 数据 dump
16 | 
17 |     public static String hexDumpReadable(ByteBuf buf) {
18 |         if (buf.readableBytes() == 0) {
19 |             return "00000000 \n";
20 |         }
21 | 
22 |         return hexDump(Arrays.copyOfRange(buf.array(), buf.readerIndex(), buf.readableBytes()), buf.readerIndex());
23 |     }
24 | 
25 |     public static String hexDumpOut(byte[] buf) {
26 |         String dump = hexDump(buf);
27 |         System.out.println(dump);
28 |         return dump;
29 |     }
30 | 
31 |     public static String hexDump(byte[] bytes) {
32 |         return hexDump(bytes, 0);
33 |     }
34 | 
35 |     public static String hexDump(byte[] bytes, int index) {
36 |         ByteArrayOutputStream os = new ByteArrayOutputStream();
37 |         try {
38 |             HexDump.dump(bytes, 0, os, index);
39 |         } catch (IOException e) {
40 |             Throwables.propagate(e);
41 |         }
42 |         return new String(os.toByteArray());
43 |     }
44 | 
45 |     // endregion
46 | 
47 | }
48 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/invoke/InputInvoke.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm.invoke;
 2 | 
 3 | import me.wener.bbvm.vm.Register;
 4 | import me.wener.bbvm.vm.SystemInvoke;
 5 | 
 6 | import javax.inject.Inject;
 7 | import javax.inject.Named;
 8 | import java.io.IOException;
 9 | import java.util.function.Supplier;
10 | 
11 | /**
12 |  * @author wener
13 |  * @since 15/12/17
14 |  */
15 | public class InputInvoke {
16 |     @Inject
17 |     @Named("R3")
18 |     private Register r3;
19 |     private Supplier supplier;
20 | 
21 |     public InputInvoke() {
22 |     }
23 | 
24 |     public InputInvoke setSupplier(Supplier supplier) {
25 |         this.supplier = supplier;
26 |         return this;
27 |     }
28 | /*
29 | 10 | 键入整数 | 0 |  | r3的值变为键入的整数
30 | 11 | 键入字符串 | 0 | r3:目标字符串句柄 | r3所指字符串的内容变为键入的字符串
31 | 12 | 键入浮点数 | 0 |  | r3的值变为键入的浮点数
32 |  */
33 | 
34 |     @SystemInvoke(type = SystemInvoke.Type.OUT, a = 10, b = 0)
35 |     public void inputInt() throws IOException {
36 |         r3.set((int) Float.parseFloat(supplier.get()));
37 |     }
38 | 
39 |     @SystemInvoke(type = SystemInvoke.Type.OUT, a = 11, b = 0)
40 |     public void inputString() throws IOException {
41 |         r3.set(supplier.get());
42 |     }
43 | 
44 |     @SystemInvoke(type = SystemInvoke.Type.OUT, a = 12, b = 0)
45 |     public void inputFloat() throws IOException {
46 |         r3.set(Float.parseFloat(supplier.get()));
47 |     }
48 | }
49 | 


--------------------------------------------------------------------------------
/bbvm/std_io.go:
--------------------------------------------------------------------------------
 1 | package bbvm
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"github.com/wenerme/bbvm/bbasm"
 7 | 	"io"
 8 | )
 9 | 
10 | func NewPrintToWriter(out io.Writer) StdBuilder {
11 | 	return func(rt bbasm.Runtime, std *Std, ) *Std {
12 | 		return &Std{
13 | 			PrintLnInt: func(ctx context.Context, v int) {
14 | 				_, _ = fmt.Fprintln(out, v)
15 | 			},
16 | 			PrintLnString: func(ctx context.Context, v StringHandler) {
17 | 				_, _ = fmt.Fprintln(out, std.StringGet(ctx, v))
18 | 			},
19 | 			PrintInt: func(ctx context.Context, v int) {
20 | 				_, _ = fmt.Fprint(out, v)
21 | 			},
22 | 			PrintString: func(ctx context.Context, v StringHandler) {
23 | 				_, _ = fmt.Fprint(out, std.StringGet(ctx, v))
24 | 			},
25 | 			PrintFloat: func(ctx context.Context, v float32) {
26 | 				_, _ = fmt.Fprintf(out, "%.6f", v)
27 | 			},
28 | 			PrintChar: func(ctx context.Context, v int) {
29 | 				_, _ = fmt.Fprintf(out, "%c", v)
30 | 			},
31 | 		}
32 | 	}
33 | }
34 | 
35 | func NewInputFromReader(in io.Reader) StdBuilder {
36 | 	return func(rt bbasm.Runtime, std *Std) *Std {
37 | 		return &Std{
38 | 			InputInt: func(ctx context.Context) (v int) {
39 | 				_, _ = fmt.Scanf("%d", &v)
40 | 				return v
41 | 			},
42 | 			InputFloat: func(ctx context.Context) (v float32) {
43 | 				_, _ = fmt.Scanf("%f", &v)
44 | 				return
45 | 			},
46 | 			InputString: func(ctx context.Context, dst StringHandler) {
47 | 				v := ""
48 | 				_, _ = fmt.Scanf("%s", &v)
49 | 				std.StringSet(ctx, dst, v)
50 | 			},
51 | 		}
52 | 	}
53 | }
54 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/Comment.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.asm;
 2 | 
 3 | import io.netty.buffer.ByteBuf;
 4 | 
 5 | /**
 6 |  * @author wener
 7 |  * @since 15/12/11
 8 |  */
 9 | public class Comment implements Assembly {
10 |     Token token;
11 | 
12 |     public Comment(Token specialToken) {
13 |         this.token = specialToken;
14 |     }
15 | 
16 |     public static Comment createFor(Token token) {
17 |         if (token.specialToken != null) {
18 |             return new Comment(token.specialToken);
19 |         }
20 |         return null;
21 |     }
22 | 
23 |     @Override
24 |     public Type getType() {
25 |         return Type.COMMENT;
26 |     }
27 | 
28 |     @Override
29 |     public String toAssembly() {
30 |         return token.toString();
31 |     }
32 | 
33 |     @Override
34 |     public Comment getComment() {
35 |         return this;
36 |     }
37 | 
38 |     @Override
39 |     public void setComment(Comment comment) {
40 |         throw new UnsupportedOperationException();
41 |     }
42 | 
43 |     @Override
44 |     public boolean hasComment() {
45 |         return true;
46 |     }
47 | 
48 |     @Override
49 |     public int length() {
50 |         return 0;
51 |     }
52 | 
53 |     @Override
54 |     public void write(ByteBuf buf) {
55 | 
56 |     }
57 | 
58 |     @Override
59 |     public int getLine() {
60 |         return token.beginLine;
61 |     }
62 | 
63 |     @Override
64 |     public String toString() {
65 |         return "Comment{" + token.toString() + "}";
66 |     }
67 | }
68 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Value.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import me.wener.bbvm.dev.Resource;
 4 | import me.wener.bbvm.dev.ResourceManager;
 5 | import me.wener.bbvm.util.IsInt;
 6 | 
 7 | /**
 8 |  * @author wener
 9 |  * @since 15/12/15
10 |  */
11 | public interface Value {
12 |     T set(int v);
13 | 
14 |     int get();
15 | 
16 |     default T set(IsInt v) {
17 |         return set(v.asInt());
18 |     }
19 | 
20 |     default T set(float v) {
21 |         return set(Float.floatToRawIntBits(v));
22 |     }
23 | 
24 |     default float getFloat() {
25 |         return Float.intBitsToFloat(get());
26 |     }
27 | 
28 |     default String getString() {
29 |         return getVm().getString(get());
30 |     }
31 | 
32 |     /**
33 |      * @param def Default value if getString return null
34 |      */
35 |     default String getString(String def) {
36 |         String s = getString();
37 |         return s == null ? def : s;
38 |     }
39 | 
40 |     default , R extends Resource> R get(M manager) {
41 |         return manager.getResource(get());
42 |     }
43 | 
44 |     @SuppressWarnings("unchecked")
45 |     default T set(String v) {
46 |         getVm().getStringManager().getResource(get()).setValue(v);
47 |         return (T) this;
48 |     }
49 | 
50 |     VM getVm();
51 | 
52 |     default T add(int v) {
53 |         return set(get() + v);
54 |     }
55 | 
56 |     default T subtract(int v) {
57 |         return set(get() - v);
58 |     }
59 | }
60 | 


--------------------------------------------------------------------------------
/cmd/bb/cmd/run.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/juju/errors"
 5 | 	"github.com/spf13/cobra"
 6 | 	"github.com/wenerme/bbvm/bbasm/parser"
 7 | 	"github.com/wenerme/bbvm/bbvm/bbrun"
 8 | 	"go.uber.org/zap"
 9 | 	"io/ioutil"
10 | 	"path"
11 | 	"strings"
12 | )
13 | 
14 | var runOpts = struct {
15 | 	Input    string
16 | 	Terminal bool
17 | }{
18 | 
19 | }
20 | var runCmd = &cobra.Command{
21 | 	Use:     "run",
22 | 	Aliases: []string{"r"},
23 | 	Run: func(cmd *cobra.Command, args []string) {
24 | 		var bin []byte
25 | 		var err error
26 | 		if !strings.HasSuffix(runOpts.Input, ".bbin") {
27 | 			zap.S().Info("try compile")
28 | 			code, err := ioutil.ReadFile(runOpts.Input)
29 | 			if err != nil {
30 | 				zap.S().With("err", err).Fatal("failed to read file")
31 | 			}
32 | 
33 | 			bin, err = parser.Compile(string(code))
34 | 			if err != nil {
35 | 				zap.S().With("err", err).Fatal("compile failed")
36 | 			}
37 | 		} else {
38 | 			bin, err = ioutil.ReadFile(runOpts.Input)
39 | 			if err != nil {
40 | 				zap.S().With("err", err).Fatal("failed to read file")
41 | 			}
42 | 		}
43 | 
44 | 		err = bbrun.Run(path.Base(runOpts.Input), bin)
45 | 		if err != nil {
46 | 			zap.S().With("err", err).Fatal("run failed")
47 | 		}
48 | 	},
49 | 	Args: func(cmd *cobra.Command, args []string) error {
50 | 		if len(args) != 1 {
51 | 			return errors.New("expect a .bbasm or .bbin to run")
52 | 		}
53 | 		runOpts.Input = args[0]
54 | 		return nil
55 | 	},
56 | }
57 | 
58 | func init() {
59 | 	rootCmd.AddCommand(runCmd)
60 | 	runCmd.Flags().BoolVarP(&runOpts.Terminal, "terminal", "t", false, "run in terminal")
61 | }
62 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingModule.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.dev.swing;
 2 | 
 3 | import com.google.inject.Exposed;
 4 | import com.google.inject.PrivateModule;
 5 | import com.google.inject.Provides;
 6 | import me.wener.bbvm.dev.*;
 7 | 
 8 | import javax.inject.Singleton;
 9 | 
10 | /**
11 |  * Provide a {@link SwingContext}
12 |  *
13 |  * @author wener
14 |  * @since 15/12/26
15 |  */
16 | public class SwingModule extends PrivateModule {
17 |     @Override
18 |     protected void configure() {
19 | 
20 |     }
21 | 
22 |     @Exposed
23 |     @Provides
24 |     @Singleton
25 |     InputManager inputManager(SwingInputManger swingInputManger) {
26 |         return swingInputManger;
27 |     }
28 | 
29 |     @Exposed
30 |     @Provides
31 |     @Singleton
32 |     FileManager fileManager(JavaFileManager javaFileManager) {
33 |         return javaFileManager;
34 |     }
35 | 
36 |     @Exposed
37 |     @Provides
38 |     @Singleton
39 |     ImageManager imageManager(SwingImageManager swingImageManager) {
40 |         return swingImageManager;
41 |     }
42 | 
43 |     @Exposed
44 |     @Provides
45 |     @Singleton
46 |     PageManager pageManager(SwingPageManager swingPageManager) {
47 |         return swingPageManager;
48 |     }
49 | 
50 |     @Exposed
51 |     @Provides
52 |     @Singleton
53 |     DeviceContext deviceContext(SwingContextImpl swingContext) {
54 |         return swingContext;
55 |     }
56 | 
57 |     @Exposed
58 |     @Provides
59 |     @Singleton
60 |     SwingContext swingContext(SwingContextImpl swingContext) {
61 |         return swingContext;
62 |     }
63 | }
64 | 


--------------------------------------------------------------------------------
/cmd/bb/cmd/compile.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/spf13/cobra"
 5 | 	"github.com/wenerme/bbvm/bbasm/parser"
 6 | 	"go.uber.org/zap"
 7 | 	"io/ioutil"
 8 | 	"path"
 9 | )
10 | 
11 | var compileOpt = struct {
12 | 	output string
13 | 	input  string
14 | }{}
15 | 
16 | var compileCmd = &cobra.Command{
17 | 	Use:     "compile",
18 | 	Aliases: []string{"c"},
19 | 	Run: func(cmd *cobra.Command, args []string) {
20 | 		if compileOpt.input == "" {
21 | 			zap.S().Fatal("missing input")
22 | 		}
23 | 
24 | 		if compileOpt.output == "" {
25 | 			if len(args) > 1 {
26 | 				compileOpt.output = args[1]
27 | 			}
28 | 		}
29 | 		if compileOpt.output == "" {
30 | 			ext := path.Ext(compileOpt.input)
31 | 			compileOpt.output = compileOpt.input[:len(compileOpt.input)-len(ext)] + ".bbin"
32 | 		}
33 | 		zap.S().Infof("compile %v to %v", compileOpt.input, compileOpt.output)
34 | 		file, err := ioutil.ReadFile(compileOpt.input)
35 | 		if err != nil {
36 | 			zap.S().With("err", err).Fatal("failed to read input %v", compileOpt.input)
37 | 		}
38 | 		bytes, err := parser.Compile(string(file))
39 | 		if err != nil {
40 | 			zap.S().With("err", err).Fatal("compile failed %v", compileOpt.input)
41 | 		}
42 | 		err = ioutil.WriteFile(compileOpt.output, bytes, 0644)
43 | 		if err != nil {
44 | 			zap.S().With("err", err).Fatal("failed to write output %v", compileOpt.output)
45 | 		}
46 | 	},
47 | }
48 | 
49 | func init() {
50 | 	rootCmd.AddCommand(compileCmd)
51 | 	compileCmd.Flags().StringVarP(&compileOpt.output, "output", "o", "", "output bbin")
52 | 	compileCmd.Flags().StringVarP(&compileOpt.input, "input", "i", "", "input bbasm")
53 | }
54 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/PseudoData.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.asm;
 2 | 
 3 | import com.google.common.collect.Lists;
 4 | import io.netty.buffer.ByteBuf;
 5 | 
 6 | import java.util.Iterator;
 7 | import java.util.List;
 8 | 
 9 | /**
10 |  * @author wener
11 |  * @since 15/12/11
12 |  */
13 | public class PseudoData extends Label implements Assembly {
14 |     Token dataTypeToken;
15 |     private List values = Lists.newArrayList();
16 | 
17 |     @Override
18 |     public Type getType() {
19 |         return Type.PSEUDO;
20 |     }
21 | 
22 |     public void add(Value data) {
23 |         values.add(data);
24 |     }
25 | 
26 |     @Override
27 |     public void write(ByteBuf buf) {
28 |         for (Value value : values) {
29 |             value.write(buf);
30 |         }
31 |     }
32 | 
33 |     @Override
34 |     public String toAssembly() {
35 |         StringBuilder sb = new StringBuilder();
36 |         sb.append("DATA ")
37 |             .append(name)
38 |             .append(' ');
39 |         if (dataTypeToken != null) {
40 |             sb.append(dataTypeToken.image).append(' ');
41 |         }
42 |         for (Iterator iterator = values.iterator(); iterator.hasNext(); ) {
43 |             sb.append(iterator.next().toAssembly());
44 |             if (iterator.hasNext()) {
45 |                 sb.append(", ");
46 |             }
47 |         }
48 |         return sb.toString();
49 |     }
50 | 
51 |     @Override
52 |     public int length() {
53 |         int len = 0;
54 |         for (Value v : values) {
55 |             len += v.length();
56 |         }
57 |         return len;
58 |     }
59 | }
60 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/PseudoBlock.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.asm;
 2 | 
 3 | import com.google.common.base.Preconditions;
 4 | import io.netty.buffer.ByteBuf;
 5 | import org.slf4j.Logger;
 6 | import org.slf4j.LoggerFactory;
 7 | 
 8 | /**
 9 |  * @author wener
10 |  * @since 15/12/11
11 |  */
12 | public class PseudoBlock extends AbstractAssembly implements Assembly {
13 |     private final static Logger log = LoggerFactory.getLogger(PseudoBlock.class);
14 |     private int length;
15 |     private int value;
16 |     private int line;
17 | 
18 |     public PseudoBlock() {
19 |     }
20 | 
21 |     public PseudoBlock(int length, int value) {
22 |         this.length = length;
23 |         this.value = value;
24 |         Preconditions.checkArgument(length >= 0);
25 |         if (value < 0 || value > 0xff) {
26 |             log.warn("BLOCK value {} will cast to {} ", value, value & 0xff);
27 |             this.value = value & 0xff;
28 |         }
29 |     }
30 | 
31 |     @Override
32 |     public Type getType() {
33 |         return Type.PSEUDO;
34 |     }
35 | 
36 |     @Override
37 |     public String toAssembly() {
38 |         return ".BLOCK " + length + " " + value;
39 |     }
40 | 
41 |     @Override
42 |     public void write(ByteBuf buf) {
43 |         for (int i = 0; i < length; i++) {
44 |             buf.writeByte(value);
45 |         }
46 |     }
47 | 
48 |     @Override
49 |     public int getLine() {
50 |         return line;
51 |     }
52 | 
53 |     public PseudoBlock setLine(int line) {
54 |         this.line = line;
55 |         return this;
56 |     }
57 | 
58 |     @Override
59 |     public int length() {
60 |         return length;
61 |     }
62 | }
63 | 


--------------------------------------------------------------------------------
/bbasm/parser/asm.go:
--------------------------------------------------------------------------------
 1 | package parser
 2 | 
 3 | import (
 4 | 	"encoding"
 5 | 	"fmt"
 6 | 	"github.com/wenerme/bbvm/bbasm"
 7 | )
 8 | 
 9 | type Assembler struct {
10 | 	Lines   []Assembly
11 | 	Symbols map[string]*Symbol
12 | 	Labels  map[string]int
13 | }
14 | 
15 | func (asm *Assembler) Assemble() ([]byte, error) {
16 | 	var o []byte
17 | 	locs := map[string]int{}
18 | 	syms := map[string]*Symbol{}
19 | 	// resolve
20 | 	track := func(a string, cb func(int)) {
21 | 		if a == "" {
22 | 			return
23 | 		}
24 | 		if syms[a] == nil {
25 | 			syms[a] = &Symbol{
26 | 				Name: a,
27 | 			}
28 | 		}
29 | 		if v, ok := locs[a]; ok {
30 | 			cb(v)
31 | 			return
32 | 		}
33 | 		s := syms[a]
34 | 		s.Reference = append(s.Reference, cb)
35 | 	}
36 | 
37 | 	loc := 0
38 | 	for _, v := range asm.Lines {
39 | 		switch a := v.(type) {
40 | 		case *Label:
41 | 			locs[a.Name] = loc
42 | 		case *PseudoData:
43 | 			locs[a.Label] = loc
44 | 		case *bbasm.Inst:
45 | 			track(a.A.Symbol, func(addr int) {
46 | 				a.A.V = int32(addr)
47 | 			})
48 | 			track(a.B.Symbol, func(addr int) {
49 | 				a.B.V = int32(addr)
50 | 			})
51 | 		}
52 | 		loc += v.Len()
53 | 	}
54 | 
55 | 	asm.Symbols = syms
56 | 	asm.Labels = locs
57 | 
58 | 	for _, v := range syms {
59 | 		if addr, ok := locs[v.Name]; ok {
60 | 			v.Address = addr
61 | 			for _, ref := range v.Reference {
62 | 				ref(addr)
63 | 			}
64 | 		} else {
65 | 			return nil, fmt.Errorf("symbol not reolve: %q", v.Name)
66 | 		}
67 | 	}
68 | 
69 | 	for _, v := range asm.Lines {
70 | 		if b, ok := v.(encoding.BinaryMarshaler); ok {
71 | 			data, err := b.MarshalBinary()
72 | 			if err != nil {
73 | 				return nil, err
74 | 			}
75 | 			o = append(o, data...)
76 | 		}
77 | 	}
78 | 	return o, nil
79 | }
80 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Symbols.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import com.google.common.collect.Maps;
 4 | 
 5 | import java.util.Collection;
 6 | import java.util.Map;
 7 | import java.util.NavigableMap;
 8 | import java.util.TreeMap;
 9 | 
10 | /**
11 |  * @author wener
12 |  * @since 15/12/11
13 |  */
14 | public class Symbols {
15 |     public static SymbolTable table(Collection symbols) {
16 |         Map nameMap = Maps.newHashMap();
17 |         NavigableMap addressMap = new TreeMap<>();
18 |         for (Symbol symbol : symbols) {
19 |             nameMap.put(symbol.getName(), symbol);
20 |             addressMap.put(symbol.getValue(), symbol);
21 |         }
22 | 
23 |         return new Table(nameMap, addressMap);
24 |     }
25 | 
26 |     private static class Table implements SymbolTable {
27 |         private Map nameMap;
28 |         private NavigableMap addressMap;
29 | 
30 |         public Table(Map nameMap, NavigableMap addressMap) {
31 |             this.nameMap = nameMap;
32 |             this.addressMap = addressMap;
33 |         }
34 | 
35 |         @Override
36 |         public Symbol getSymbol(String name) {
37 |             return nameMap.get(name);
38 |         }
39 | 
40 |         @Override
41 |         public Symbol getSymbol(int address) {
42 |             return addressMap.get(address);
43 |         }
44 | 
45 |         @Override
46 |         public Map getNameMap() {
47 |             return nameMap;
48 |         }
49 | 
50 |         @Override
51 |         public NavigableMap getAddressMap() {
52 |             return addressMap;
53 |         }
54 |     }
55 | }
56 | 


--------------------------------------------------------------------------------
/bbasm/parser/pseudo_data.go:
--------------------------------------------------------------------------------
 1 | package parser
 2 | 
 3 | import (
 4 | 	"encoding/binary"
 5 | 	"encoding/hex"
 6 | 	"fmt"
 7 | 	"github.com/juju/errors"
 8 | 	"strconv"
 9 | )
10 | 
11 | type pseudoDataInt int32
12 | 
13 | func (v pseudoDataInt) MarshalBinary() (data []byte, err error) {
14 | 	data = make([]byte, 4)
15 | 	binary.LittleEndian.PutUint32(data, uint32(v))
16 | 	return
17 | }
18 | func (v pseudoDataInt) Len() int {
19 | 	return 4
20 | }
21 | func (v pseudoDataInt) Assembly() string {
22 | 	return strconv.Itoa(int(v))
23 | }
24 | 
25 | type pseudoDataStr []byte
26 | 
27 | func (v pseudoDataStr) MarshalBinary() ([]byte, error) {
28 | 	return v, nil
29 | }
30 | func (v pseudoDataStr) Len() int {
31 | 	return len(v)
32 | }
33 | func (v pseudoDataStr) Assembly() string {
34 | 	return fmt.Sprintf(`"%s"`, string(v))
35 | }
36 | 
37 | type pseudoDataBytes []byte
38 | 
39 | func (v pseudoDataBytes) MarshalBinary() ([]byte, error) {
40 | 	return v, nil
41 | }
42 | func (v pseudoDataBytes) Len() int {
43 | 	return len(v)
44 | }
45 | func (v pseudoDataBytes) Assembly() string {
46 | 	return fmt.Sprintf(`%%%s%%`, hex.EncodeToString(v))
47 | }
48 | 
49 | func createPseudoDataValue(v interface{}) (d PseudoDataValue, e error) {
50 | 	switch v.(type) {
51 | 	case int:
52 | 		d = pseudoDataInt(v.(int))
53 | 	case string:
54 | 		b := []byte(v.(string))
55 | 		switch b[0] {
56 | 		case '"':
57 | 			d = pseudoDataStr(b[1 : len(b)-1])
58 | 		case '%':
59 | 			b, e := hex.DecodeString(string(b[1 : len(b)-1]))
60 | 			if e != nil {
61 | 				return nil, e
62 | 			}
63 | 			d = pseudoDataBytes(b)
64 | 		default:
65 | 			e = errors.Errorf("Currently can not create pseudo data value by %#v", v)
66 | 		}
67 | 	// TODO Symbol reference
68 | 	default:
69 | 		e = errors.Errorf("Can not create pseudo data value by %#v", v)
70 | 	}
71 | 	return
72 | }
73 | 


--------------------------------------------------------------------------------
/jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Opcode.java:
--------------------------------------------------------------------------------
 1 | package me.wener.bbvm.vm;
 2 | 
 3 | import com.google.common.collect.Maps;
 4 | import me.wener.bbvm.util.IsInt;
 5 | 
 6 | import java.util.EnumMap;
 7 | 
 8 | /**
 9 |  * 指令集
10 |  * 
11 |  * NOP	| 0x0
12 |  * LD     | 0x1
13 |  * PUSH   | 0x2
14 |  * POP    | 0x3
15 |  * IN     | 0x4
16 |  * OUT    | 0x5
17 |  * JMP    | 0x6
18 |  * JPC    | 0x7
19 |  * CALL   | 0x8
20 |  * RET    | 0x9
21 |  * CMP    | 0xA
22 |  * CAL    | 0xB
23 |  * EXIT   | 0xF
24 |  * 
25 | */ 26 | public enum Opcode implements IsInt { 27 | NOP(0x0), 28 | LD(0x1), 29 | PUSH(0x2), 30 | POP(0x3), 31 | IN(0x4), 32 | OUT(0x5), 33 | JMP(0x6), 34 | JPC(0x7), 35 | CALL(0x8), 36 | RET(0x9), 37 | CMP(0xA), 38 | CAL(0xB), 39 | EXIT(0xF); 40 | private final static EnumMap length; 41 | 42 | static { 43 | length = Maps.newEnumMap(Opcode.class); 44 | length.put(NOP, 1); 45 | length.put(LD, 10); 46 | length.put(PUSH, 5); 47 | length.put(POP, 5); 48 | length.put(IN, 10); 49 | length.put(OUT, 10); 50 | length.put(JMP, 5); 51 | length.put(JPC, 6); 52 | length.put(CALL, 5); 53 | length.put(RET, 1); 54 | length.put(CMP, 10); 55 | length.put(CAL, 10); 56 | length.put(EXIT, 1); 57 | } 58 | 59 | private final int value; 60 | 61 | 62 | Opcode(int value) { 63 | this.value = value; 64 | } 65 | 66 | /** 67 | * 获取对应指令的长度 68 | */ 69 | public static Integer length(Opcode instruction) { 70 | return length.get(instruction); 71 | } 72 | 73 | public int length() { 74 | return length(this); 75 | } 76 | 77 | public int asInt() { 78 | return value; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/dev/swing/ImagesTest.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import me.wener.bbvm.dev.swing.Images.ImageInfo; 4 | import org.junit.Test; 5 | 6 | import javax.imageio.ImageIO; 7 | import java.io.File; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author wener 12 | * @since 15/12/20 13 | */ 14 | public class ImagesTest { 15 | 16 | @Test(expected = Exception.class) 17 | public void testFileNotFound() throws IOException { 18 | Images.load("../bbvm-test/image/9288-xxxx.lib").get(0); 19 | } 20 | 21 | @Test 22 | public void testLib2BitLeGray() throws IOException { 23 | ImageInfo info = Images.load("../bbvm-test/image/9288.lib").get(0); 24 | ImageIO.write(Images.read(info), "png", new File(info.getType() + ".png")); 25 | } 26 | 27 | @Test 28 | public void testLib2BitBeGray() throws IOException { 29 | ImageInfo info = Images.load("../bbvm-test/image/9188.lib").get(0); 30 | ImageIO.write(Images.read(info), "png", new File(info.getType() + ".png")); 31 | } 32 | 33 | @Test 34 | public void testLibRGB565() throws IOException { 35 | ImageInfo info = Images.load("../bbvm-test/image/9688.lib").get(0); 36 | ImageIO.write(Images.read(info), "BMP", new File(info.getType() + ".bmp")); 37 | } 38 | 39 | @Test 40 | public void testRlb() throws IOException { 41 | ImageInfo info = Images.load("../bbvm-test/image/bmp.rlb").get(0); 42 | ImageIO.write(Images.read(info), "BMP", new File(info.getType() + ".bmp")); 43 | } 44 | 45 | @Test 46 | public void testGeneric() throws IOException { 47 | ImageInfo info = Images.load("../bbvm-test/image/bmp.bmp").get(0); 48 | ImageIO.write(Images.read(info), "BMP", new File(info.getType() + ".bmp")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/Node.java: -------------------------------------------------------------------------------- 1 | /* Generated By:JJTree: Do not edit this line. Node.java Version 6.1 */ 2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ 3 | package me.wener.bbvm.asm; 4 | 5 | /* All AST nodes must implement this interface. It provides basic 6 | machinery for constructing the parent and child relationships 7 | between nodes. */ 8 | 9 | public interface Node { 10 | 11 | /** 12 | * This method is called after the node has been made the current 13 | * node. It indicates that child nodes can now be added to it. 14 | */ 15 | public void jjtOpen(); 16 | 17 | /** 18 | * This method is called after all the child nodes have been 19 | * added. 20 | */ 21 | public void jjtClose(); 22 | 23 | /** 24 | * This pair of methods are used to inform the node of its 25 | * parent. 26 | */ 27 | public void jjtSetParent(Node n); 28 | 29 | public Node jjtGetParent(); 30 | 31 | /** 32 | * This method tells the node to add its argument to the node's 33 | * list of children. 34 | */ 35 | public void jjtAddChild(Node n, int i); 36 | 37 | /** 38 | * This method returns a child node. The children are numbered 39 | * from zero, left to right. 40 | */ 41 | public Node jjtGetChild(int i); 42 | 43 | /** 44 | * Return the number of children the node has. 45 | */ 46 | public int jjtGetNumChildren(); 47 | 48 | public int getId(); 49 | 50 | /** 51 | * Accept the visitor. 52 | **/ 53 | public Object jjtAccept(BBAsmParserVisitor visitor, Object data); 54 | } 55 | /* JavaCC - OriginalChecksum=2fac2e112494d94a94a98dc639cfb76b (do not edit this line) */ 56 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/invoke/OutputInvoke.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm.invoke; 2 | 3 | import me.wener.bbvm.vm.Operand; 4 | import me.wener.bbvm.vm.SystemInvoke; 5 | 6 | import java.util.function.Consumer; 7 | 8 | /** 9 | * @author wener 10 | * @since 15/12/22 11 | */ 12 | public class OutputInvoke { 13 | private final Consumer consumer; 14 | 15 | public OutputInvoke(Consumer consumer) { 16 | this.consumer = consumer; 17 | } 18 | 19 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 0) 20 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 1) 21 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 2) 22 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 3) 23 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 4) 24 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 5) 25 | public void out(Operand a, Operand b) { 26 | switch (a.get()) { 27 | case 0: 28 | println(String.valueOf(b.get())); 29 | break; 30 | case 1: 31 | println(b.getString()); 32 | break; 33 | case 2: 34 | print(b.getString()); 35 | break; 36 | case 4: 37 | print(String.valueOf(Character.toChars(b.get())[0])); 38 | break; 39 | case 3: 40 | print(String.valueOf(b.get())); 41 | break; 42 | case 5: 43 | float v = b.getFloat(); 44 | print(String.format("%.6f", v)); 45 | break; 46 | } 47 | } 48 | 49 | protected void print(String s) { 50 | consumer.accept(s); 51 | } 52 | 53 | protected void println(String s) { 54 | consumer.accept(s); 55 | consumer.accept("\n"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/PageResource.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | /** 4 | * @author wener 5 | * @since 15/12/18 6 | */ 7 | public interface PageResource extends Resource, Drawable { 8 | @Override 9 | PageManager getManager(); 10 | 11 | PageResource draw(Drawable o, int dx, int dy, int w, int h, int x, int y, int mode); 12 | 13 | /** 14 | * Display on screen 15 | */ 16 | PageResource display(); 17 | 18 | PageResource draw(PageResource resource); 19 | 20 | PageResource fill(int x, int y, int w, int h, int rgb); 21 | 22 | PageResource pixel(int x, int y, int rgb); 23 | 24 | int pixel(int x, int y); 25 | 26 | /** 27 | * Clear page, fill with pen color, reset locate 28 | */ 29 | PageResource clear(); 30 | 31 | PageResource draw(PageResource resource, int x, int y); 32 | 33 | PageResource draw(PageResource resource, int x, int y, int w, int h, int cx, int cy); 34 | 35 | PageResource pen(int width, int style, int rgb); 36 | 37 | PageResource circle(int cx, int cy, int r); 38 | 39 | PageResource rectangle(int left, int top, int right, int bottom); 40 | 41 | PageResource line(int x, int y); 42 | 43 | PageResource move(int x, int y); 44 | 45 | /** 46 | * Position of cursor in font size column, start from 1 47 | */ 48 | PageResource locate(int row, int column); 49 | 50 | /** 51 | * Position of cursor in pixel 52 | */ 53 | PageResource cursor(int row, int column); 54 | 55 | PageResource draw(String text); 56 | 57 | /** 58 | * Change the font 59 | */ 60 | PageResource font(int font); 61 | 62 | /** 63 | * Set the font style 64 | */ 65 | PageResource font(int frontColor, int backColor, int frame); 66 | 67 | /** 68 | * @see DeviceConstants.BackgroundMode 69 | */ 70 | PageResource setBackgroundMode(int mode); 71 | } 72 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingContextImpl.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import me.wener.bbvm.dev.*; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Singleton; 7 | import javax.swing.*; 8 | 9 | /** 10 | * @author wener 11 | * @since 15/12/26 12 | */ 13 | @Singleton 14 | class SwingContextImpl implements SwingContext { 15 | private JFrame frame; 16 | @Inject 17 | private SwingPageManager pageManager; 18 | @Inject 19 | private SwingInputManger inputManger; 20 | @Inject 21 | private SwingImageManager imageManager; 22 | @Inject 23 | private JavaFileManager fileManager; 24 | @Inject 25 | private StringManager stringManager; 26 | private Thread refreshThread; 27 | 28 | 29 | @Override 30 | public JFrame getFrame() { 31 | if (frame == null) { 32 | synchronized (this) { 33 | if (frame == null) { 34 | frame = createFrame(); 35 | } 36 | } 37 | } 38 | return frame; 39 | } 40 | 41 | @Override 42 | public PageManager getPageManager() { 43 | return pageManager; 44 | } 45 | 46 | @Override 47 | public ImageManager getImageManager() { 48 | return imageManager; 49 | } 50 | 51 | @Override 52 | public InputManager getInputManager() { 53 | return inputManger; 54 | } 55 | 56 | @Override 57 | public FileManager getFileManager() { 58 | return fileManager; 59 | } 60 | 61 | @Override 62 | public StringManager getStringManager() { 63 | return stringManager; 64 | } 65 | 66 | protected JFrame createFrame() { 67 | MainFrame frame = new MainFrame(() -> pageManager.getScreen().getImage()); 68 | inputManger.bindKeyEvent(frame); 69 | inputManger.bindMouseEvent(frame.getImagePanel()); 70 | return frame; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /bbasm/parser/parser.go: -------------------------------------------------------------------------------- 1 | //go:generate peg -switch bbasm.peg 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | /* 10 | A parser has a context 11 | contain 12 | labels 13 | assemblies 14 | this context is not belong to parser 15 | asm should hold this context 16 | will used in 17 | linking 18 | resolve label reference 19 | debugging 20 | resolve label name 21 | when doing REPL, this context is not enough, the running vm hold 22 | memory 23 | stack 24 | register 25 | system calling handler 26 | 27 | asm 28 | only define the assemblies and types 29 | parser 30 | parse a line to an assembly 31 | vm 32 | memory 33 | stack 34 | register 35 | system calling handler 36 | 37 | Problem 38 | who load the file 39 | who hold the label table 40 | who group them together 41 | 42 | While REPL 43 | every line will parse 44 | resolve label reference 45 | execute by vm 46 | 47 | While running 48 | file will parse 49 | add to context 50 | */ 51 | 52 | func Compile(s string) ([]byte, error) { 53 | assemblies, err := Parse(s) 54 | 55 | if err != nil { 56 | return nil, err 57 | } 58 | asm := &Assembler{Lines: assemblies} 59 | return asm.Assemble() 60 | } 61 | 62 | func ParseLine(s string) (Assembly, error) { 63 | assemblies, err := Parse(s) 64 | if err != nil { 65 | return nil, err 66 | } 67 | if len(assemblies) != 1 { 68 | return nil, fmt.Errorf("expect one line got: %v", len(assemblies)) 69 | } 70 | return assemblies[0], nil 71 | } 72 | func Parse(s string) ([]Assembly, error) { 73 | p := &BBAsm{Buffer: s} 74 | p.Init() 75 | if err := p.Parse(); err != nil { 76 | return nil, err 77 | } 78 | // fixme 79 | var err error 80 | func() { 81 | defer func() { 82 | if r := recover(); r != nil { 83 | if e, ok := r.(error); ok { 84 | err = e 85 | } else { 86 | err = fmt.Errorf("err %v", e) 87 | } 88 | } 89 | }() 90 | p.Execute() 91 | }() 92 | return p.assemblies, err 93 | } 94 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/AbstractFileManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | import com.google.common.eventbus.EventBus; 4 | import com.google.common.eventbus.Subscribe; 5 | import me.wener.bbvm.exception.ExecutionException; 6 | import me.wener.bbvm.vm.event.ResetEvent; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.inject.Inject; 11 | import java.nio.charset.Charset; 12 | 13 | /** 14 | * @author wener 15 | * @since 15/12/26 16 | */ 17 | public abstract class AbstractFileManager implements FileManager { 18 | protected final static Logger log = LoggerFactory.getLogger(FileManager.class); 19 | static final int HANDLER_NUMBER = 10; 20 | protected final FileResource[] resources = new FileResource[HANDLER_NUMBER]; 21 | @Inject 22 | protected Charset charset; 23 | 24 | protected abstract FileResource createResource(int i); 25 | 26 | @Override 27 | public FileResource getResource(int handler) { 28 | if (handler < 0 || handler > HANDLER_NUMBER) { 29 | throw new ExecutionException("No file resource for handler " + handler); 30 | } 31 | return resources[handler]; 32 | } 33 | 34 | @Override 35 | public AbstractFileManager reset() { 36 | for (FileResource resource : resources) { 37 | resource.close(); 38 | } 39 | return this; 40 | } 41 | 42 | @Override 43 | public FileResource create() { 44 | throw new ExecutionException("Resource for file is fixed"); 45 | } 46 | 47 | @Inject 48 | void init(EventBus eventBus) { 49 | eventBus.register(this); 50 | 51 | for (int i = 0; i < HANDLER_NUMBER; i++) { 52 | resources[i] = createResource(i); 53 | } 54 | 55 | } 56 | 57 | @Subscribe 58 | public void onReset(ResetEvent resetEvent) { 59 | log.debug("Reset all file resources"); 60 | reset(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/invoke/KeyInvoke.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm.invoke; 2 | 3 | import me.wener.bbvm.dev.InputManager; 4 | import me.wener.bbvm.vm.Register; 5 | import me.wener.bbvm.vm.SystemInvoke; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.inject.Inject; 10 | import javax.inject.Named; 11 | 12 | /** 13 | * @author wener 14 | * @since 15/12/20 15 | */ 16 | public class KeyInvoke { 17 | private final static Logger log = LoggerFactory.getLogger(KeyInvoke.class); 18 | private final Register r3; 19 | private final Register r2; 20 | private final Register r1; 21 | private final Register r0; 22 | private InputManager inputManager; 23 | 24 | @Inject 25 | public KeyInvoke(@Named("R3") Register r3, @Named("R2") Register r2, @Named("R1") Register r1, @Named("R0") Register r0, InputManager inputManager) { 26 | this.r3 = r3; 27 | this.r2 = r2; 28 | this.r1 = r1; 29 | this.r0 = r0; 30 | this.inputManager = inputManager; 31 | } 32 | 33 | /* 34 | 10 | 键入整数 | 0 | | r3的值变为键入的整数 35 | 11 | 键入字符串 | 0 | r3:目标字符串句柄 | r3所指字符串的内容变为键入的字符串 36 | 12 | 键入浮点数 | 0 | | r3的值变为键入的浮点数 37 | 38 | 34 | 判定某键是否按下 | 0;r3 | r3:KEY | KEYPRESS(KEY) 39 | 39 | 等待按键 | r3:按键 | - | WAITKEY() 40 | 45 | 获取按键的字符串 | 0 | r3:字符串句柄,用于存储结果 | InKey$ 41 | 46 | 获取按键的ASCII码 | 0 | r3:KEYPRESS | INKEY() 42 | */ 43 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 34, b = 0) 44 | public void keyPress() { 45 | r3.set(inputManager.isKeyPressed(r3.get()) ? 1 : 0); 46 | } 47 | 48 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 39, b = 0) 49 | public void waitKey() { 50 | r3.set(inputManager.waitKey()); 51 | } 52 | 53 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 45, b = 0) 54 | public void keyString() { 55 | r3.set(inputManager.inKeyString()); 56 | } 57 | 58 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 46, b = 0) 59 | public void keyCode() { 60 | r3.set(inputManager.inKey()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /cmd/bb/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/spf13/cobra" 6 | "github.com/wenerme/bbvm/bbvm/fyneui" 7 | "go.uber.org/zap" 8 | "os" 9 | 10 | homedir "github.com/mitchellh/go-homedir" 11 | "github.com/spf13/viper" 12 | ) 13 | 14 | var cfgFile string 15 | 16 | // rootCmd represents the base command when called without any subcommands 17 | var rootCmd = &cobra.Command{ 18 | Use: "bb", 19 | Short: "bb is a tool for BeBasic Source Code and Virtual Machine", 20 | Long: ``, 21 | Run: func(cmd *cobra.Command, args []string) { 22 | fyneui.RunApp(nil) 23 | }, 24 | } 25 | 26 | var rootOpts = struct { 27 | debug bool 28 | }{} 29 | 30 | // Execute adds all child commands to the root command and sets flags appropriately. 31 | // This is called by main.main(). It only needs to happen once to the rootCmd. 32 | func Execute() { 33 | if err := rootCmd.Execute(); err != nil { 34 | fmt.Println(err) 35 | os.Exit(1) 36 | } 37 | } 38 | 39 | func init() { 40 | cobra.OnInitialize(initConfig) 41 | rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is bb.yaml)") 42 | rootCmd.PersistentFlags().BoolVarP(&rootOpts.debug, "debug", "D", false, "enable debug") 43 | } 44 | 45 | // initConfig reads in config file and ENV variables if set. 46 | func initConfig() { 47 | if cfgFile != "" { 48 | // Use config file from the flag. 49 | viper.SetConfigFile(cfgFile) 50 | } else { 51 | // Find home directory. 52 | home, err := homedir.Dir() 53 | if err != nil { 54 | fmt.Println(err) 55 | os.Exit(1) 56 | } 57 | 58 | // Search config in home directory with name ".bb" (without extension). 59 | viper.AddConfigPath(home) 60 | viper.SetConfigName(".bb") 61 | } 62 | 63 | viper.AutomaticEnv() // read in environment variables that match 64 | 65 | // If a config file is found, read it in. 66 | if err := viper.ReadInConfig(); err == nil { 67 | fmt.Println("Using config file:", viper.ConfigFileUsed()) 68 | } 69 | 70 | if rootOpts.debug { 71 | logger, _ := zap.NewDevelopmentConfig().Build() 72 | zap.ReplaceGlobals(logger) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/build.gradle: -------------------------------------------------------------------------------- 1 | description = 'Be Basic virtual machine core module' 2 | dependencies { 3 | compile group: 'com.google.inject', name: 'guice', version: '4.0' 4 | compile group: 'com.google.inject.extensions', name: 'guice-multibindings', version: '4.0' 5 | compile group: 'org.gwizard', name: 'gwizard-services', version: '0.6' 6 | compile group: 'com.typesafe', name: 'config', version: '1.2.1' 7 | compile group: 'com.google.guava', name: 'guava', version: '19.0' 8 | compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4' 9 | compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.7' 10 | compile group: 'commons-io', name: 'commons-io', version: '2.4' 11 | compile group: 'io.netty', name: 'netty-buffer', version: '4.0.33.Final' 12 | compile group: 'com.intellij', name: 'annotations', version: '12.0' 13 | // Optional https://issues.gradle.org/browse/GRADLE-1749 14 | compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0' 15 | testCompile group: 'junit', name: 'junit', version: '4.12' 16 | testCompile group: 'org.assertj', name: 'assertj-swing-junit', version: '3.0.2' 17 | } 18 | 19 | apply plugin: "ca.coglinc.javacc" 20 | 21 | buildscript { 22 | repositories { 23 | mavenLocal() 24 | mavenCentral() 25 | maven { 26 | url "https://plugins.gradle.org/m2/" 27 | } 28 | } 29 | 30 | dependencies { 31 | classpath "ca.coglinc:javacc-gradle-plugin:2.3.1" 32 | } 33 | } 34 | 35 | compileJjtree { 36 | inputDirectory = file('src/main/jjtree') 37 | outputDirectory = file(project.buildDir.absolutePath + '/generated/jjtree') 38 | } 39 | 40 | 41 | apply plugin: 'jacoco' 42 | apply plugin: 'com.github.kt3k.coveralls' 43 | 44 | buildscript { 45 | repositories { 46 | mavenLocal() 47 | mavenCentral() 48 | } 49 | 50 | dependencies { 51 | classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1' 52 | } 53 | } 54 | 55 | jacocoTestReport { 56 | reports { 57 | xml.enabled = true 58 | html.enabled = true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /bbasm/parser/build.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/juju/errors" 5 | "github.com/ngaut/log" 6 | "github.com/wenerme/bbvm/bbasm" 7 | "strings" 8 | ) 9 | 10 | func buildInst(a *bbasm.Inst, v ...interface{}) error { 11 | n := 0 12 | switch a.Opcode { 13 | case bbasm.JMP, bbasm.PUSH, bbasm.POP, bbasm.CALL: 14 | n = 1 15 | case bbasm.IN, bbasm.OUT, bbasm.JPC: 16 | n = 2 17 | case bbasm.LD, bbasm.CMP: 18 | n = 3 19 | case bbasm.CAL: 20 | n = 4 21 | } 22 | if len(v) != n { 23 | return errors.Errorf("Expecte %v for %v got %v", n, a.Opcode, len(v)) 24 | } 25 | 26 | operands := 0 27 | for _, o := range v { 28 | switch o.(type) { 29 | case *bbasm.Operand: 30 | switch operands { 31 | case 0: 32 | a.A = *(o.(*bbasm.Operand)) 33 | case 1: 34 | a.B = *(o.(*bbasm.Operand)) 35 | default: 36 | return errors.New("To many operands") 37 | } 38 | operands++ 39 | case bbasm.DataType: 40 | a.DataType = o.(bbasm.DataType) 41 | case bbasm.CompareType: 42 | a.CompareType = o.(bbasm.CompareType) 43 | case bbasm.CalculateType: 44 | a.CalculateType = o.(bbasm.CalculateType) 45 | default: 46 | return errors.Errorf("Unexpected value %#v", o) 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | func buildComment(a *Comment, v ...interface{}) error { 53 | a.Content = strings.Trim(v[0].(string), " \t") 54 | return nil 55 | } 56 | 57 | func buildLabel(a *Label, v ...interface{}) error { 58 | a.Name = strings.Trim(v[0].(string), " \t") 59 | return nil 60 | } 61 | 62 | func buildPseudoBlock(a *PseudoBlock, v ...interface{}) error { 63 | if len(v) != 2 { 64 | return errors.Errorf(".BLOCK size byte got %v", v) 65 | } 66 | a.Size = v[0].(int) 67 | i64 := v[1].(int) 68 | if int32(i64%0xff) != int32(i64) { 69 | log.Warnf("Convert %v to byte", i64) 70 | } 71 | a.Byte = byte(i64) 72 | return nil 73 | } 74 | 75 | func buildPseudoData(a *PseudoData, v ...interface{}) error { 76 | a.Label = v[0].(string) 77 | a.Values = make([]PseudoDataValue, len(v)-1) 78 | for i, v := range v[1:] { 79 | if v, ok := v.(PseudoDataValue); ok { 80 | a.Values[i] = v 81 | } else { 82 | return errors.Errorf("Require PseudoDataValue got %#v", v) 83 | } 84 | } 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /bbasm/exec.go: -------------------------------------------------------------------------------- 1 | package bbasm 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math" 7 | ) 8 | 9 | func Execute(ctx context.Context, rt Runtime, inst *Inst) { 10 | a := inst.A 11 | b := inst.B 12 | 13 | switch inst.Opcode { 14 | case NOP: 15 | // Tick 16 | case LD: 17 | a.Set(b.Get()) 18 | case PUSH: 19 | rt.Push(a.Get()) 20 | case POP: 21 | a.Set(rt.Pop()) 22 | case IN: 23 | rt.In(ctx,a.Get(), b.Get()) 24 | case OUT: 25 | rt.Out(ctx,a.Get(), b.Get()) 26 | case JMP: 27 | rt.Jump(a.Get()) 28 | case JPC: 29 | if inst.CompareType.IsMatch(CompareType(rt.Register(RF).Get())) { 30 | rt.Jump(a.Get()) 31 | } 32 | case CALL: 33 | // 压入下一条指令的位置 34 | rt.Push(rt.Register(RP).Get() + inst.Opcode.Len()) 35 | rt.Jump(a.Get()) 36 | case RET: 37 | rt.Jump(rt.Pop()) 38 | case CMP: 39 | rt.Register(RF).Set(Compare(a, b, inst.DataType)) 40 | case CAL: 41 | a.Set(Calculate(a.Get(), b.Get(), inst.CalculateType, inst.DataType)) 42 | case EXIT: 43 | rt.Exit() 44 | } 45 | } 46 | 47 | func Compare(a Operand, b Operand, d DataType) int { 48 | v := float32(0) 49 | if d == FLOAT { 50 | v = a.Float() - b.Float() 51 | } else { 52 | v = float32(a.Get() - b.Get()) 53 | } 54 | switch { 55 | case v > 0: 56 | return 1 57 | case v < 0: 58 | return -1 59 | default: 60 | return 0 61 | } 62 | } 63 | 64 | func Calculate(a int, b int, t CalculateType, d DataType) int { 65 | var oa, ob, oc float64 66 | if d == FLOAT { 67 | oa = float64(math.Float32frombits(uint32(a))) 68 | ob = float64(math.Float32frombits(uint32(b))) 69 | } else { 70 | oa = float64(a) 71 | ob = float64(b) 72 | } 73 | switch t { 74 | case ADD: 75 | oc = oa + ob 76 | case SUB: 77 | oc = oa - ob 78 | case MUL: 79 | oc = oa * ob 80 | case DIV: 81 | oc = oa / ob 82 | case MOD: 83 | oc = float64(int(oa) % int(ob)) 84 | default: 85 | panic(fmt.Errorf("invalid calc %v", t.String())) 86 | } 87 | var ret int 88 | switch d { 89 | case DWORD: 90 | ret = int(oc) 91 | case WORD: 92 | ret = int(int16(oc)) 93 | case BYTE: 94 | ret = int(byte(oc)) 95 | case FLOAT: 96 | ret = int(math.Float32bits(float32(oc))) 97 | case INT: 98 | ret = int(oc) 99 | default: 100 | panic(fmt.Errorf("invalid datatype %v", t.String())) 101 | } 102 | return ret 103 | } 104 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/DeviceConstants.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | import me.wener.bbvm.util.IsInt; 4 | import org.intellij.lang.annotations.MagicConstant; 5 | 6 | /** 7 | * Predefined device relate constants 8 | * 9 | * @author wener 10 | * @since 15/12/26 11 | */ 12 | public interface DeviceConstants { 13 | // Brush Style 14 | int BRUSH_SOLID = 0; 15 | 16 | // Pen style 17 | int PEN_SOLID = 0; 18 | int PEN_DASH = 1; 19 | 20 | // Env type 21 | int ENV_SIM = 0; 22 | int ENV_9288 = 9288; 23 | int ENV_9188 = 9188; 24 | int ENV_9288T = 9287; 25 | int ENV_9288S = 9286; 26 | int ENV_9388 = 9388; 27 | int ENV_9688 = 9688; 28 | 29 | /** 30 | * Draw image with key color 31 | */ 32 | int DRAW_KEY_COLOR = 1; 33 | /** 34 | * No font background 35 | */ 36 | int BACKGROUND_TRANSPARENT = 1; 37 | 38 | /** 39 | * With font background 40 | */ 41 | int BACKGROUND_OPAQUE = 2; 42 | 43 | enum FontType implements IsInt { 44 | FONT_12SONG(0, 12), 45 | FONT_12KAI(1, 12), 46 | FONT_12HEI(2, 12), 47 | FONT_16SONG(3, 16), 48 | FONT_16KAI(4, 16), 49 | FONT_16HEI(5, 16), 50 | FONT_24SONG(6, 24), 51 | FONT_24KAI(7, 24), 52 | FONT_24HEI(8, 24); 53 | private final int value; 54 | private final int size; 55 | 56 | FontType(int value, int size) { 57 | this.value = value; 58 | this.size = size; 59 | } 60 | 61 | public int asInt() { 62 | return value; 63 | } 64 | 65 | public int getSize() { 66 | return size; 67 | } 68 | } 69 | 70 | // enum BackgroundMode implements IsInt { 71 | // /** 72 | // * 透明显示,即字体的背景颜色无效。 73 | // */ 74 | // TRANSPARENT(1), 75 | // /** 76 | // * 不透明显示,即字体的背景颜色有效 77 | // */ 78 | // OPAQUE(2); 79 | // private final int value; 80 | // 81 | // BackgroundMode(int value) { 82 | // this.value = value; 83 | // } 84 | // 85 | // public int asInt() { 86 | // return value; 87 | // } 88 | // } 89 | 90 | @MagicConstant(intValues = {ENV_SIM, ENV_9188, ENV_9288, ENV_9288S, ENV_9288T, ENV_9388, ENV_9688}) 91 | @interface Env { 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /bbvm/std_base.go: -------------------------------------------------------------------------------- 1 | package bbvm 2 | 3 | import ( 4 | "context" 5 | "github.com/wenerme/bbvm/bbasm" 6 | "math" 7 | "math/rand" 8 | "time" 9 | ) 10 | 11 | func StdBase(rt bbasm.Runtime, std *Std) *Std { 12 | random := rand.New(rand.NewSource(0)) 13 | dataPtr := 0 14 | return &Std{ 15 | FloatToInt: func(ctx context.Context, v float32) int { 16 | return int(v) 17 | }, 18 | IntToFloat: func(ctx context.Context, v int) float32 { 19 | return float32(v) 20 | }, 21 | Sin: func(ctx context.Context, a float32) float32 { 22 | return float32(math.Sin(float64(a))) 23 | }, 24 | Cos: func(ctx context.Context, a float32) float32 { 25 | return float32(math.Cos(float64(a))) 26 | }, 27 | Tan: func(ctx context.Context, a float32) float32 { 28 | return float32(math.Tan(float64(a))) 29 | }, 30 | Sqrt: func(ctx context.Context, a float32) float32 { 31 | return float32(math.Sqrt(float64(a))) 32 | }, 33 | IntAbs: func(ctx context.Context, a int) int { 34 | if a >= 0 { 35 | return a 36 | } 37 | return -a 38 | }, 39 | FloatAbs: func(ctx context.Context, a float32) float32 { 40 | if a >= 0 { 41 | return a 42 | } 43 | return -a 44 | }, 45 | Delay: func(ctx context.Context, msec int) { 46 | time.Sleep(time.Duration(msec) * time.Millisecond) 47 | }, 48 | Tick: func(ctx context.Context) int { 49 | return int(time.Now().Unix()) 50 | }, 51 | Read: func(ctx context.Context, addr int) int { 52 | return rt.GetInt(addr) 53 | }, 54 | Write: func(ctx context.Context, addr int, v int) { 55 | rt.SetInt(addr, v) 56 | }, 57 | GetEnv: func(ctx context.Context) int { 58 | // Sim 59 | return 0 60 | }, 61 | DataPtrSet: func(ctx context.Context, v int) { 62 | dataPtr = v 63 | }, 64 | DataReadInt: func(ctx context.Context) int { 65 | v := rt.GetInt(dataPtr) 66 | dataPtr += 4 67 | return v 68 | }, 69 | DataReadFloat: func(ctx context.Context) float32 { 70 | v := rt.GetFloat(dataPtr) 71 | dataPtr += 4 72 | return v 73 | }, 74 | DataReadString: func(ctx context.Context, hdr StringHandler) { 75 | v := rt.GetString(dataPtr) 76 | bytes, _ := std.StringToBytes(v) 77 | dataPtr += len(bytes) 78 | std.StringSet(ctx, hdr, v) 79 | }, 80 | RandSeed: func(ctx context.Context, seed int) { 81 | random.Seed(int64(seed)) 82 | }, 83 | Rand: func(ctx context.Context, n int) int { 84 | return random.Intn(n) 85 | }, 86 | VmTest: func(ctx context.Context) { 87 | }, 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /jbbvm/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /bbasm/operand.go: -------------------------------------------------------------------------------- 1 | package bbasm 2 | 3 | import ( 4 | "fmt" 5 | "github.com/spacemonkeygo/errors" 6 | "math" 7 | ) 8 | 9 | var ErrDataToShort = errors.NewClass("ErrDataToShort") 10 | var ErrWrongInst = errors.NewClass("ErrWrongInst") 11 | 12 | type Operand struct { 13 | V int32 // Address or Immediate value 14 | AddressMode AddressMode 15 | RT Runtime 16 | Symbol string // Symbol associated to this operand - run from assembly 17 | } 18 | 19 | func (o *Operand) Get() int { 20 | switch o.AddressMode { 21 | case AddressRegister: 22 | return o.RT.Register(RegisterType(o.V)).Get() 23 | case AddressRegisterDeferred: 24 | return o.RT.GetInt(o.RT.Register(RegisterType(o.V)).Get()) 25 | case AddressImmediate: 26 | return int(int32(o.V)) // must convert to int32 first 27 | case AddressDirect: 28 | return o.RT.GetInt(int(o.V)) 29 | } 30 | panic(fmt.Errorf("invalid %v", o.AddressMode.String())) 31 | } 32 | func (o *Operand) Float() float32 { 33 | return math.Float32frombits(uint32(o.Get())) 34 | } 35 | func (o *Operand) SetFloat(v float32) { 36 | o.Set(int(int32(math.Float32bits(v)))) // Must conver to int32 first 37 | } 38 | 39 | //func (o *Operand) Str() string { 40 | // //if s, err := o.VM.GetStr(o.Get()); err == nil { 41 | // // return s 42 | // //}else { 43 | // // //log.Error("Operand string res %d not exists: %s", o.Get(), err.Error()) 44 | // // return "" 45 | // //} 46 | // // FIXME 47 | // return "" 48 | //} 49 | //func (o *Operand) SetStr(v string) { 50 | // //if r := o.StrRes(); r != nil { 51 | // // o.StrRes().Set(v) 52 | // //}else { 53 | // // //log.Error("Operand string res %d not exists", o.Get()) 54 | // //} 55 | // // FIXME 56 | //} 57 | 58 | func (o *Operand) Set(i int) { 59 | switch o.AddressMode { 60 | case AddressRegister: 61 | o.RT.Register(RegisterType(o.V)).Set(i) 62 | case AddressRegisterDeferred: 63 | o.RT.SetInt(o.RT.Register(RegisterType(o.V)).Get(), i) 64 | case AddressImmediate: 65 | panic("ERR Set a IMMEDIATE operand") 66 | case AddressDirect: 67 | o.RT.SetInt(int(o.V), i) 68 | default: 69 | panic("ERR Unknown address mode when set operand") 70 | } 71 | } 72 | 73 | func (o Operand) String() string { 74 | switch o.AddressMode { 75 | case AddressRegister: 76 | return fmt.Sprintf("%s", RegisterType(o.V)) 77 | case AddressRegisterDeferred: 78 | return fmt.Sprintf("[ %s ]", RegisterType(o.V)) 79 | case AddressImmediate: 80 | if o.Symbol == "" { 81 | return fmt.Sprintf("%v", o.V) 82 | } else { 83 | return fmt.Sprintf("%v", o.Symbol) 84 | } 85 | case AddressDirect: 86 | if o.Symbol == "" { 87 | return fmt.Sprintf("[ %v ]", o.V) 88 | } else { 89 | return fmt.Sprintf("[ %v ]", o.Symbol) 90 | } 91 | } 92 | return "ERR Unknown address mode " + o.AddressMode.String() 93 | } 94 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/Label.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.asm; 2 | 3 | import com.google.common.base.MoreObjects; 4 | import com.google.common.collect.Lists; 5 | import me.wener.bbvm.vm.Operand; 6 | import me.wener.bbvm.vm.Symbol; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author wener 12 | * @since 15/12/11 13 | */ 14 | public class Label extends AbstractAssembly implements Symbol, Assembly { 15 | String name; 16 | int value = -1; 17 | /** 18 | * Operands referenced to this label 19 | */ 20 | List operands = Lists.newArrayList(); 21 | Token token; 22 | 23 | public Label() { 24 | } 25 | 26 | public Label(String name, Token token) { 27 | this.token = token; 28 | this.name = name; 29 | } 30 | 31 | public Label(String name) { 32 | this.name = name; 33 | } 34 | 35 | public Token getToken() { 36 | return token; 37 | } 38 | 39 | public Label setToken(Token token) { 40 | this.token = token; 41 | return this; 42 | } 43 | 44 | public int getValue() { 45 | return value; 46 | } 47 | 48 | public Label setValue(int value) { 49 | this.value = value; 50 | for (OperandInfo info : operands) { 51 | info.operand.setInternal(value); 52 | } 53 | return this; 54 | } 55 | 56 | @Override 57 | public String getName() { 58 | return name; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return MoreObjects.toStringHelper(this) 64 | .add("name", name) 65 | .add("value", value) 66 | .add("comment", comment) 67 | .add("line", token != null ? token.beginLine : -1) 68 | .add("column", token != null ? token.beginColumn : -1) 69 | .toString(); 70 | } 71 | 72 | public void addOperand(Token token, Operand operand) { 73 | operand.setSymbol(this).setInternal(value); 74 | operands.add(new Label.OperandInfo(operand, token)); 75 | } 76 | 77 | @Override 78 | public Type getType() { 79 | return Type.LABEL; 80 | } 81 | 82 | @Override 83 | public String toAssembly() { 84 | return token.toString() + commentAssembly(); 85 | } 86 | 87 | @Override 88 | public int getLine() { 89 | return token == null ? -1 : token.beginLine; 90 | } 91 | 92 | static class OperandInfo { 93 | Operand operand; 94 | Token token; 95 | 96 | public OperandInfo(Operand operand, Token token) { 97 | this.operand = operand; 98 | this.token = token; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/TestUtil.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm; 2 | 3 | 4 | import com.google.common.base.Predicate; 5 | import com.google.common.base.Strings; 6 | import com.google.common.collect.Lists; 7 | import io.netty.buffer.ByteBuf; 8 | import io.netty.buffer.Unpooled; 9 | import org.apache.commons.io.HexDump; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.IOException; 14 | import java.nio.ByteOrder; 15 | import java.util.List; 16 | import java.util.regex.Pattern; 17 | import java.util.stream.Collectors; 18 | 19 | public class TestUtil { 20 | public static final Pattern MATCH_HEX_DATA = Pattern 21 | .compile("\\s{2,}([^ \r\n]*[^0-9a-fA-F]+[^ \r\n]*)$", Pattern.MULTILINE); 22 | public static final Pattern MATCH_OFFSET = Pattern 23 | .compile("^[^\\s]+\\s", Pattern.MULTILINE); 24 | public static final Predicate NON_NULL_OR_EMPTY = new Predicate() { 25 | @Override 26 | public boolean apply(String input) { 27 | return !Strings.isNullOrEmpty(input); 28 | } 29 | }; 30 | private final static Logger log = LoggerFactory.getLogger(TestUtil.class); 31 | protected static boolean logDump = false; 32 | 33 | public static ByteBuf fromDumpBytes(String dump) { 34 | ByteBuf buf = Unpooled.buffer(20); 35 | String origin = dump; 36 | // 删除偏移值 37 | if (dump.startsWith("00000000 ")) 38 | dump = MATCH_OFFSET.matcher(dump).replaceAll(""); 39 | dump = MATCH_HEX_DATA.matcher(dump).replaceAll(""); 40 | String[] lines = dump.split("[\n\r]+"); 41 | for (String line : lines) { 42 | Iterable iterable = Lists.newArrayList(line.split("\\s+")).stream().filter(NON_NULL_OR_EMPTY::apply).collect(Collectors.toList()); 43 | List split = Lists.newArrayList(iterable); 44 | // 一行最多16个 45 | for (int i = 0; i < split.size() && i < 16; i++) { 46 | String b = split.get(i); 47 | buf.writeByte(Integer.parseInt(b, 16)); 48 | } 49 | } 50 | 51 | if (log.isTraceEnabled() || logDump) 52 | try { 53 | System.out.println("原始内容"); 54 | System.out.println(origin); 55 | System.out.println("解析结果 长度:" + buf.readableBytes()); 56 | HexDump.dump(buf.copy().array(), 0, System.out, 0); 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | 61 | return buf.order(ByteOrder.LITTLE_ENDIAN); 62 | } 63 | 64 | public static byte[] readableToBytes(ByteBuf buf) { 65 | byte[] bytes = new byte[buf.readableBytes()]; 66 | buf.readBytes(bytes); 67 | return bytes; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/BasmSpecTest.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm; 2 | 3 | import com.google.common.base.Splitter; 4 | import com.typesafe.config.Config; 5 | import com.typesafe.config.ConfigFactory; 6 | import me.wener.bbvm.asm.ParseException; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.io.PrintStream; 14 | import java.nio.file.Files; 15 | import java.nio.file.Paths; 16 | 17 | /** 18 | * @author wener 19 | * @since 15/12/18 20 | */ 21 | public class BasmSpecTest { 22 | private final static Logger log = LoggerFactory.getLogger(BasmSpecTest.class); 23 | 24 | @Test 25 | public void in() throws IOException, ParseException { 26 | doTest("../bbvm-test/case/in"); 27 | } 28 | 29 | @Test 30 | public void out() throws IOException, ParseException { 31 | doTest("../bbvm-test/case/out"); 32 | } 33 | 34 | @Test 35 | public void file() throws IOException, ParseException { 36 | doTest("../bbvm-test/case/file"); 37 | } 38 | 39 | @Test 40 | public void graph() throws IOException, ParseException { 41 | doTest("../bbvm-test/case/graph"); 42 | } 43 | 44 | @Test 45 | public void basic() throws IOException, ParseException { 46 | doTest("../bbvm-test/case/basic"); 47 | } 48 | 49 | private void doTest(String first) throws IOException { 50 | BasmTester test = new BasmTester(); 51 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 52 | test.setPrintStream(new PrintStream(out)); 53 | Splitter.MapSplitter separator = Splitter.on('&').omitEmptyStrings().withKeyValueSeparator('='); 54 | Files.walk(Paths.get(first)) 55 | .filter(p -> !p.toFile().isDirectory()) 56 | .filter(p -> p.toFile().getName().endsWith(".basm")) 57 | .forEach(p -> { 58 | BasmTester tester = test; 59 | String fn = com.google.common.io.Files.getNameWithoutExtension(p.toString()); 60 | if (fn.contains("=")) { 61 | Config config = ConfigFactory.parseMap(separator.split(fn)); 62 | tester = new BasmTester(config); 63 | log.info("Create BasmTester for {} -> {}", config, p); 64 | } 65 | 66 | // When test failed, we need the output 67 | try { 68 | out.reset(); 69 | tester.init(p.toFile()).run(); 70 | } catch (Throwable e) { 71 | System.out.println(out.toString()); 72 | System.out.println("Test failed for " + p); 73 | e.printStackTrace(); 74 | throw e; 75 | } 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /bbasm/parser/bbasm_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davecgh/go-spew/spew" 6 | "github.com/pkg/errors" 7 | "github.com/stretchr/testify/assert" 8 | "io/ioutil" 9 | "log" 10 | "os" 11 | "path" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func TestBBAsm(t *testing.T) { 17 | b, e := ioutil.ReadFile("testdata/exp.txt") 18 | if e != nil { 19 | panic(e) 20 | } 21 | code := string(b) 22 | p := &BBAsm{Buffer: code} 23 | p.Init() 24 | if err := p.Parse(); err != nil { 25 | for i, c := range strings.Split(code, "\n") { 26 | if trim(c) == "" { 27 | continue 28 | } 29 | p := &BBAsm{Buffer: c} 30 | p.Init() 31 | e := p.Parse() 32 | if e != nil { 33 | panic(errors.Wrapf(e, "Pase failed line %v : %v", i+1, c)) 34 | } 35 | p.Execute() 36 | } 37 | } 38 | // p.PrintSyntaxTree() 39 | 40 | func() { 41 | defer func() { 42 | if e := recover(); e != nil { 43 | spew.Dump(p.stack) 44 | fmt.Println("----------------------------------------------") 45 | for _, a := range p.assemblies { 46 | fmt.Println(a.Assembly()) 47 | } 48 | if e, ok := e.(error); ok { 49 | panic(e) 50 | } else { 51 | panic(e) 52 | } 53 | } 54 | 55 | }() 56 | p.Execute() 57 | }() 58 | 59 | spew.Dump(p.stack) 60 | for _, a := range p.assemblies { 61 | fmt.Println(a.Assembly()) 62 | } 63 | } 64 | 65 | func TestParseCase(t *testing.T) { 66 | log.SetFlags(log.Ltime | log.Llongfile) 67 | log.SetOutput(os.Stderr) 68 | assert := assert.New(t) 69 | parseWholeDir("../testdata/case", assert) 70 | } 71 | 72 | func parseWholeDir(dir string, assert *assert.Assertions) { 73 | f, e := os.Open(dir) 74 | assert.NoError(e) 75 | fi, e := f.Readdir(-1) 76 | assert.NoError(e) 77 | for _, f := range fi { 78 | if f.IsDir() { 79 | parseWholeDir(path.Join(dir, f.Name()), assert) 80 | } else if strings.HasSuffix(f.Name(), ".basm") { 81 | if strings.Contains(f.Name(), "=") { 82 | fmt.Printf("Ignore %v case\n", path.Join(dir, f.Name())) 83 | } else { 84 | testParse(path.Join(dir, f.Name()), assert) 85 | } 86 | } 87 | 88 | } 89 | } 90 | func testParse(f string, assert *assert.Assertions) { 91 | fmt.Println("Parse ", f) 92 | b, e := ioutil.ReadFile(f) 93 | assert.NoError(e) 94 | p := &BBAsm{Buffer: string(b)} 95 | func() { 96 | defer func() { 97 | if e := recover(); e != nil { 98 | spew.Dump(p.stack) 99 | fmt.Println("-------------------- PARSE FAILED --------------------------") 100 | for _, a := range p.assemblies { 101 | fmt.Println(a.Assembly()) 102 | } 103 | if e, ok := e.(error); ok { 104 | panic(e) 105 | } else { 106 | panic(e) 107 | } 108 | } 109 | 110 | }() 111 | 112 | p.Init() 113 | if err := p.Parse(); err != nil { 114 | panic(err) 115 | } 116 | p.Execute() 117 | }() 118 | } 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BBVM - BeBasic Virtual Machine 2 | =========================== 3 | [![Build Status](https://travis-ci.org/wenerme/bbvm.svg)](https://travis-ci.org/wenerme/bbvm) 4 | [![Coverage Status](https://coveralls.io/repos/wenerme/bbvm/badge.svg?branch=master&service=github)](https://coveralls.io/github/wenerme/bbvm?branch=master) 5 | [![Build with love](https://img.shields.io/badge/bbvm-%F0%9F%92%97-orange.svg)](https://github.com/wenerme) 6 | [![GitHub issues](https://img.shields.io/github/issues/wenerme/bbvm.svg)](https://github.com/wenerme/bbvm/issues) 7 | [![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/wenerme/bbvm/master/LICENSE) 8 | [![Twitter](https://img.shields.io/twitter/url/https/github.com/wenerme/bbvm.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=https://github.com/wenerme/bbvm/) 9 | 10 | ``` 11 | ; ____________________ 12 | ; \______ \______ \___ _______ 13 | ; | | _/| | _/\ \/ / \ 14 | ; | | \| | \ \ / Y Y \ 15 | ; |______ /|______ / \_/|__|_| / 16 | ; \/ \/ \/ 17 | 18 | JMP CODE 19 | DATA STR CHAR "Hello, BBvm",0 20 | CODE: 21 | 22 | OUT 1, STR 23 | EXIT 24 | ``` 25 | 26 | ``` 27 | >Hello, BBvm 28 | ``` 29 | 30 | --- 31 | 32 | ```bash 33 | go get github.com/wenerme/bbvm/cmd/bb # Install bb command tool 34 | bb run examples/hello.bbasm # Directly run bbasm 35 | 36 | bb compile -o hello.bbin -i examples/hello.bbasm # Compile bbasm to bbin 37 | bb run hello.bbin # Run bbin 38 | hexdump -C hello.bbin 39 | 40 | go get github.com/wenerme/bbvm/cmd/bbin # Bundled bbin 41 | bbin # Should output: Hello BBvm 42 | ``` 43 | 44 | | 中文 | English | 45 | |:----:|:----:| 46 | | [README](#BB虚拟机)/[WIKI](https://github.com/wenerme/bbvm/wiki/主页) | [README](#bbvm)/[WIKI](https://github.com/wenerme/bbvm/wiki/Home) | 47 | 48 | ![大富翁](doc/image/bbvm-monopoly-demo.png) 49 | 50 | # BBvm 51 | 52 | BBvm is a simple easy virtual machine that run bbin compile from bbasm which is a simple assembly too. 53 | 54 | ## Features 55 | 56 | BBvm has a lot built-in system invoke with a default screen enabled device. 57 | 58 | * Graphic draw 59 | * Image load 60 | * File read/write 61 | * String op 62 | 63 | --- 64 | 65 | # BB虚拟机 66 | 67 | BBvm 是一个简单的虚拟机,其汇编码为 BBasm. 68 | 69 | ## 主要功能 70 | 71 | BBvm 包含了大量的内建系统调用,并且运行于一个有屏幕的设备上. 72 | 73 | * 图形操作 74 | * 图像操作 75 | * 文件操作 76 | * 字符串操作 77 | 78 | ## BBasic 79 | 80 | [BBasic](http://www.baike.com/wiki/BBASIC) 是一种掌上学习机的编程平台.BBK BBASIC,简称BB,最早由通宵虫于2006年开发,是由VMBASIC结合QuickBASIC开发而成. 81 | 运行于早期步步高学习机平台. 82 | 83 | 该项目为原步步高 BBasic 虚拟机的一个仿照实现.并在原来的基础上进行了扩展. 84 | 85 | * 做到和 BBasic 的汇编码兼容 86 | * 做到和 BBasic 的二进制兼容 87 | * 实现编译 Vasm 的编译器 88 | * 实现 BB 的虚拟机,包括图形界面等所有功能 89 | * 对 BBAsm 进行扩展 90 | 91 | 参考 92 | ==== 93 | 94 | 95 | 96 | * BBAsm 语法参考[这里][bbasm-g4] 97 | * BB 虚拟机规范参考[这里][bbvm-spec] 98 | 99 | [bbasm-g4]:https://github.com/wenerme/bbvm/blob/master/doc/grammar/BBAsm.g4 100 | [bbvm-spec]:https://github.com/wenerme/bbvm/wiki/vm-spec 101 | 102 | 103 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/MainFrame.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.ComponentAdapter; 9 | import java.awt.event.ComponentEvent; 10 | import java.awt.image.BufferedImage; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.ScheduledExecutorService; 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.function.Supplier; 15 | 16 | /** 17 | * @author wener 18 | * @since 15/12/28 19 | */ 20 | // Handle the image change on reset ---- by using supplier 21 | // Create a custom component to contain image and refresh ---- by using image panel 22 | // Handle image resize ---- by monitor image 23 | public class MainFrame extends JFrame { 24 | private final static Logger log = LoggerFactory.getLogger(MainFrame.class); 25 | private final Supplier image; 26 | private ImagePanel imagePanel; 27 | private ScheduledExecutorService refresher; 28 | 29 | public MainFrame(Supplier image) throws HeadlessException { 30 | super("BBVM"); 31 | this.image = new MonitoredImage(image); 32 | initialize(); 33 | } 34 | 35 | protected void initialize() { 36 | setFocusTraversalKeysEnabled(false);// Make VK_TAB works 37 | setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 38 | setResizable(false); 39 | 40 | imagePanel = new ImagePanel(image); 41 | imagePanel.setLocation(0, 0); 42 | getContentPane().add(imagePanel); 43 | getImage(); 44 | 45 | addComponentListener(new ComponentAdapter() { 46 | @Override 47 | public void componentShown(ComponentEvent e) { 48 | log.debug("Show frame, start refresher thread."); 49 | refresher = Executors.newSingleThreadScheduledExecutor(); 50 | refresher.scheduleAtFixedRate(imagePanel::refresh, 0, 1000 / 16, TimeUnit.MILLISECONDS); 51 | } 52 | 53 | @Override 54 | public void componentHidden(ComponentEvent e) { 55 | log.debug("Hide frame, stop refresher thread."); 56 | refresher.shutdownNow(); 57 | } 58 | }); 59 | } 60 | 61 | private Image getImage() { 62 | return image.get(); 63 | } 64 | 65 | public void setImageSize(int width, int height) { 66 | SwingUtilities.invokeLater(() -> { 67 | setSize(width, height); 68 | imagePanel.setPreferredSize(getSize()); 69 | pack(); 70 | setLocationRelativeTo(null); 71 | }); 72 | } 73 | 74 | public ImagePanel getImagePanel() { 75 | return imagePanel; 76 | } 77 | 78 | class MonitoredImage implements Supplier { 79 | private final Supplier image; 80 | int w, h; 81 | 82 | MonitoredImage(Supplier image) { 83 | this.image = image; 84 | } 85 | 86 | @Override 87 | public BufferedImage get() { 88 | BufferedImage i = image.get(); 89 | if (i.getWidth() != w || i.getHeight() != h) { 90 | setImageSize(w = i.getWidth(), h = i.getHeight()); 91 | } 92 | return i; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/vm/Dumps.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import me.wener.bbvm.TestUtil; 5 | 6 | public class Dumps extends TestUtil { 7 | 8 | public static String simpleInstAsm() { 9 | return "CALL LABEL0 ; For initialization\n" + 10 | "LD dword R2,CD_INITDATA\n" + 11 | "IN R2,22\n" + 12 | "PUSH [CSTRING_3]\n" + 13 | "POP R2\n" + 14 | "IN R3,2\n" + 15 | "IN R2,5\n" + 16 | "PUSH R3\n" + 17 | "POP R3\n" + 18 | "OUT 2,R3\n" + 19 | "IN R3,8\n" + 20 | "OUT 4,10\n" + 21 | "EXIT\n" + 22 | "LABEL0:\n" + 23 | "LD dword [CSTRING_3],CS_CSTRING_3\n" + 24 | "RET\n" + 25 | "LABEL1:\n" + 26 | "EXIT\n" + 27 | "LABEL2:\n" + 28 | "DATA CSTRING_3 dword 0\n" + 29 | "DATA CS_CSTRING_3 char \"ABC\",0\n" + 30 | "DATA CD_INITDATA bin %%"; 31 | } 32 | 33 | public static ByteBuf simpleInst() { 34 | String dump = "00000000 42 42 45 00 00 00 00 40 00 00 00 00 00 00 00 00 |BBE....@........|\n" + 35 | "00000010 82 60 00 00 00 10 02 06 00 00 00 77 00 00 00 40 |.`.........w...@|\n" + 36 | "00000020 02 06 00 00 00 16 00 00 00 23 6c 00 00 00 30 06 |.........#l...0.|\n" + 37 | "00000030 00 00 00 40 02 07 00 00 00 02 00 00 00 40 02 06 |...@.........@..|\n" + 38 | "00000040 00 00 00 05 00 00 00 20 07 00 00 00 30 07 00 00 |....... ....0...|\n" + 39 | "00000050 00 50 08 02 00 00 00 07 00 00 00 40 02 07 00 00 |.P.........@....|\n" + 40 | "00000060 00 08 00 00 00 50 0a 04 00 00 00 0a 00 00 00 f0 |.....P..........|\n" + 41 | "00000070 10 0e 6c 00 00 00 70 00 00 00 90 f0 00 00 00 00 |..l...p.........|\n" + 42 | "00000080 41 42 43 00 00 00 00 |ABC....|"; 43 | return fromDumpBytes(dump); 44 | } 45 | 46 | public static String jmpAndCalAsm() { 47 | return "JPC A R1\n" + 48 | "JPC NZ 2\n" + 49 | "JPC B 3\n" + 50 | "JPC AE [ LABEL5 ]\n" + 51 | "JPC BE [ R2 ]\n" + 52 | "PUSH 1\n" + 53 | "JMP LABEL6\n" + 54 | "CAL int ADD R0,R1\n" + 55 | "CAL float sub R0,[1]\n" + 56 | "CAL word mul R2,[LABEL5]\n" + 57 | "CAL dword mod R3,[LABEL6]\n" + 58 | "CAL byte div RP,R3\n" + 59 | "LABEL5:\n" + 60 | "LABEL6:"; 61 | } 62 | 63 | public static ByteBuf jmpAndCal() { 64 | String dump = "00000000 42 42 45 00 00 00 00 40 00 00 00 00 00 00 00 00 |BBE....@........|\n" + 65 | "00000010 74 00 05 00 00 00 76 02 02 00 00 00 72 02 03 00 |t.....v.....r...|\n" + 66 | "00000020 00 00 75 03 5a 00 00 00 73 01 06 00 00 00 22 01 |..u.Z...s.....\".|\n" + 67 | "00000030 00 00 00 62 5a 00 00 00 b4 00 04 00 00 00 05 00 |...bZ...........|\n" + 68 | "00000040 00 00 b3 13 04 00 00 00 01 00 00 00 b1 23 06 00 |.............#..|\n" + 69 | "00000050 00 00 5a 00 00 00 b0 43 07 00 00 00 5a 00 00 00 |..Z....C....Z...|\n" + 70 | "00000060 b2 30 00 00 00 00 07 00 00 00 |.0........|\n"; 71 | return fromDumpBytes(dump); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /doc/bbvm.txt: -------------------------------------------------------------------------------- 1 | java.io.DataInputStream 2 | ByteBuffer 3 | http://slick.ninjacave.com/ 4 | https://github.com/preon/preon 5 | 6 | Preon aims to provide a framework for dealing with binary encoded data; or more specifically, it aims to deal with situations in which bytes are considered to be overkill. The project is named after the "point-like" particles, conceived to be subcomponents of quarks and leptons. Let's just say very small particles that you don't see with the naked eye, but you probably rely on them without knowing. 7 | 8 | Preon is to bitstream encoded content what JAXB is to XML, or Hibernate to relational databases. You define your in memory representation of the data structure in Java classes, and add annotations to 'tell' how it should be mapped onto a bitstream encoded representation. Preon takes care of the rest: it will give you a decoder, hyperlinked documentation on the encoding format, and - if you want - annotated hexdumps explaining you exactly what you're looking at. 9 | 10 | http://jparsec.codehaus.org/ 11 | 12 | Jparsec is a recursive-desent parser combinator framework written for Java. It constructs parsers in native Java language only. 13 | 14 | Why yet another parser framework? 15 | --------------------------------- 16 | Jparsec stands out for its combinator nature. It is no parser generator like YACC or ANTLR. No extra grammar file is required. Grammar is written in native Java /C# language, which also means you can utilize all the utilities in the Java/.Net community to get your parser fancy. 17 | 18 | What does "jparsec" stand for? 19 | ------------------------------- 20 | Jparsec is an implementation of Haskell Parsec on the Java platform. 21 | 22 | Feature highlights. 23 | ------------------- 24 | * operator precendence grammar. 25 | * accurate error location and customizable error message. 26 | * rich set of pre-defined reusable combinator functions. 27 | * declarative API that resembles BNF. 28 | 29 | https://code.google.com/p/java-binary-block-parser/ 30 | 31 | Introduction 32 | ------------- 33 | Sometime it is very important to parse in Java some binary block data, may be not in very fast way but structures can be complicated and byte and bit orders can be very different. In Python we have the Struct package for operations to parse binary blocks but in Java such operations look a bit verbose and take some time to be programmed, so that I decided during my vacation to develop a framework which would decrease verbosity for such operations in Java and will decrease my work in future because I am too lazy to write a lot of code. 34 | 35 | Java support 36 | ------------ 37 | The Framework developed to support Java platform since Java SE 1.5+, its inside mapping has been developed in such manner to support work under the Android platform so that the framework is an Android compatible one. It doesn't use any NIO and usage of the non-standard sun.misc.unsafe class is isolated with reflection. 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 构架 51 | BBVm 52 | 需要读取bin文件 53 | 需要针对每个指令解析,然后使用每个指令进行相应操作 54 | 需要记录寄存器值 55 | 读取bin的时候 需要能够随时跳转 56 | 提供gui操作接口 57 | Image操作接口 58 | 抽象BB里的一些概念 59 | 屏幕 60 | 读pixel 61 | 写pixel 62 | 图像资源集合 63 | 切换屏幕 64 | IO 65 | 66 | 67 | Device 68 | 设备需要提供 page 句柄和 图片资源句柄 69 | HandlerPool 70 | HandlerPool 71 | 72 | Page 需要封装和具体平台相关的显示的东西 73 | 74 | 75 | 76 | 77 | 一个 VM 一个上下文 78 | 一个上下文中的 Operand 和 Register 都不会变 79 | 通过 Name + 类型来注入 Operand 和 Register 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Memory.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import com.google.common.base.MoreObjects; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | 7 | import java.nio.ByteOrder; 8 | import java.nio.charset.Charset; 9 | 10 | /** 11 | * @author wener 12 | * @since 15/12/10 13 | */ 14 | public class Memory { 15 | public static final int DEFAULT_MEMORY = 1024 * 1024 * 4; 16 | public static final int DEFAULT_STACK_SIZE = 1000; 17 | Register rs; 18 | Register rb; 19 | private ByteBuf mem; 20 | private int memorySize; 21 | private int stackSize; 22 | private VM vm; 23 | 24 | private Memory() { 25 | this(DEFAULT_MEMORY, DEFAULT_STACK_SIZE); 26 | } 27 | 28 | private Memory(int memorySize, int stackSize) { 29 | mem = Unpooled.buffer(memorySize + stackSize, memorySize + stackSize).order(ByteOrder.LITTLE_ENDIAN); 30 | this.stackSize = stackSize; 31 | this.memorySize = memorySize; 32 | } 33 | 34 | public static Memory load(ByteBuf buf) { 35 | Memory memory = new Memory(buf.readableBytes(), DEFAULT_STACK_SIZE); 36 | memory.mem.writeBytes(buf); 37 | return memory; 38 | } 39 | 40 | /** 41 | * Fill memory with zero 42 | */ 43 | public Memory clear() { 44 | mem.clear(); 45 | byte[] bytes = mem.array(); 46 | for (int i = 0; i < bytes.length; i++) { 47 | bytes[i] = 0; 48 | } 49 | return this; 50 | } 51 | 52 | public VM getVm() { 53 | return vm; 54 | } 55 | 56 | public Memory setVm(VM vm) { 57 | this.vm = vm; 58 | this.rs = vm.rs; 59 | this.rb = vm.rb; 60 | return this; 61 | } 62 | 63 | public int pop() { 64 | rs.add(4); 65 | return mem.getInt(rs.get()); 66 | } 67 | 68 | public void push(int v) { 69 | // TODO Stack bounds check 70 | // if (rb.intValue() - rs.intValue() < 4) { 71 | // throw new RuntimeException("Stack overflow"); 72 | // } 73 | mem.setInt(rs.get(), v); 74 | rs.subtract(4); 75 | } 76 | 77 | public ByteBuf getByteBuf() { 78 | return mem; 79 | } 80 | 81 | public int getMemorySize() { 82 | return memorySize; 83 | } 84 | 85 | public int getStackSize() { 86 | return stackSize; 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return MoreObjects.toStringHelper(this) 92 | .add("mem", mem) 93 | .add("rs", rs) 94 | .add("rb", rb) 95 | .add("memorySize", memorySize) 96 | .add("stackSize", stackSize) 97 | .toString(); 98 | } 99 | 100 | public int read(int addr) { 101 | return mem.getInt(addr); 102 | } 103 | 104 | public Memory write(int addr, int v) { 105 | mem.setInt(addr, v); 106 | return this; 107 | } 108 | 109 | public String getString(int i, Charset charset) { 110 | int end = i; 111 | byte[] bytes = mem.array(); 112 | //noinspection StatementWithEmptyBody 113 | while (bytes[end++] != 0) { 114 | // Ignored 115 | } 116 | int length = end - i - 1; 117 | if (length == 0) { 118 | return ""; 119 | } 120 | return new String(bytes, i, length, charset); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/test/java/me/wener/bbvm/vm/TestSpec.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import com.google.common.base.Joiner; 4 | import com.google.common.base.Splitter; 5 | import com.google.common.collect.Lists; 6 | 7 | import java.util.List; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * 从 asm 中抽取输入输出 16 | * 17 | * @author wener 18 | * @since 15/12/15 19 | */ 20 | public class TestSpec { 21 | public static final Pattern REG_MARKER = Pattern.compile(";\\s*(\\|?[><])(.+)"); 22 | public static final Splitter NL_SPLITTER = Splitter.on('\n'); 23 | public static final Joiner NL_JOINER = Joiner.on('\n'); 24 | private final StringBuilder input = new StringBuilder(); 25 | private final StringBuilder output = new StringBuilder(); 26 | 27 | public TestSpec clear() { 28 | input.setLength(0); 29 | output.setLength(0); 30 | return this; 31 | } 32 | 33 | public TestSpec accept(String c) { 34 | StringBuilder in = new StringBuilder(); 35 | StringBuilder out = new StringBuilder(); 36 | Matcher matcher = REG_MARKER.matcher(c); 37 | while (matcher.find()) { 38 | String type = matcher.group(1); 39 | String content = matcher.group(2).trim(); 40 | if (content.length() == 0) { 41 | continue; 42 | } 43 | switch (type) { 44 | case "<": 45 | in.append(content).append('\n'); 46 | break; 47 | case "|<": 48 | in.append(content); 49 | break; 50 | case ">": 51 | out.append(content).append('\n'); 52 | break; 53 | case "|>": 54 | out.append(content); 55 | break; 56 | default: 57 | throw new AssertionError(); 58 | } 59 | } 60 | input(in); 61 | output(out); 62 | return this; 63 | } 64 | 65 | public TestSpec input(CharSequence c) { 66 | input.append(c); 67 | return this; 68 | } 69 | 70 | public TestSpec output(CharSequence c) { 71 | output.append(c); 72 | return this; 73 | } 74 | 75 | public CharSequence output() { 76 | return output; 77 | } 78 | 79 | public CharSequence input() { 80 | return input; 81 | } 82 | 83 | public void assertMatch(String out) { 84 | List skipped = Lists.newArrayList(); 85 | List expected = NL_SPLITTER.splitToList(output); 86 | for (int i = 0; i < expected.size(); i++) { 87 | if (expected.get(i).equals("skip")) { 88 | skipped.add(i); 89 | } 90 | } 91 | List actually = Lists.newArrayList(NL_SPLITTER.splitToList(out)); 92 | 93 | try { 94 | assertEquals(expected.size(), actually.size()); 95 | } catch (Throwable e) { 96 | System.out.printf("Expected\n%s\nActually\n%s\n", output, out); 97 | throw e; 98 | } 99 | 100 | skipped.forEach(i -> actually.set(i, "skip")); 101 | assertThat(NL_JOINER.join(actually)).isEqualTo(NL_JOINER.join(expected)); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/StringDrawer.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import java.awt.*; 4 | import java.awt.geom.Rectangle2D; 5 | 6 | /** 7 | * @author wener 8 | * @since 15/12/26 9 | */ 10 | class StringDrawer { 11 | protected final Graphics2D g; 12 | int x, y, w, h; 13 | private FontMetrics metrics; 14 | private int fontHeight; 15 | private Color front = Color.WHITE; 16 | private Color back = Color.BLACK; 17 | private boolean backgroundVisible; 18 | private FontMetrics fm; 19 | // private Consumer nextPage = (d) -> d.g.fillRect(0, 0, w, h); 20 | 21 | StringDrawer(Graphics2D g, int w, int h) { 22 | this.g = g; 23 | this.w = w; 24 | this.h = h; 25 | fontChanged(); 26 | locate(1, 1); 27 | } 28 | 29 | /** 30 | * Notify font changed 31 | */ 32 | public void fontChanged() { 33 | metrics = g.getFontMetrics(); 34 | // Font font = g.getFont(); 35 | fm = g.getFontMetrics(); 36 | fontHeight = fm.getHeight(); 37 | } 38 | 39 | /** 40 | * Start from 1 41 | */ 42 | public void locate(int row, int column) { 43 | int width = g.getFont().getSize(); 44 | x = (column - 1) * width / 2; 45 | y = row * width; 46 | } 47 | 48 | public void cursor(int row, int column) { 49 | x = column; 50 | y = row; 51 | } 52 | 53 | public void draw(String text) { 54 | text.chars().forEach(this::draw); 55 | } 56 | 57 | public void draw(int ch) { 58 | switch (ch) { 59 | case '\n': 60 | nextCursorLine(); 61 | break; 62 | case '\t': 63 | for (int i = 0; i < 8; i++) { 64 | drawNormal(' '); 65 | } 66 | break; 67 | default: 68 | drawNormal(ch); 69 | } 70 | } 71 | 72 | private void advanceCursor(int width) { 73 | x += width; 74 | if (x > w) { 75 | nextCursorLine(); 76 | } 77 | } 78 | 79 | void drawNormal(int ch) { 80 | String s = String.valueOf((char) ch); 81 | int width = metrics.charWidth(ch); 82 | if (x + width > w) { 83 | nextCursorLine(); 84 | } 85 | if (backgroundVisible) { 86 | Rectangle2D rect = fm.getStringBounds(s, g); 87 | g.setColor(back); 88 | g.fillRect(x, 89 | y - fm.getAscent(), 90 | (int) rect.getWidth(), 91 | fontHeight); 92 | } 93 | // Draw char 94 | g.setColor(front); 95 | g.drawString(s, x, y); 96 | advanceCursor(width); 97 | } 98 | 99 | void nextCursorLine() { 100 | x = 0; 101 | y += fontHeight; 102 | if (y + fontHeight > h) {// Not enough 103 | nextPage(); 104 | } 105 | } 106 | 107 | private void nextPage() { 108 | locate(1, 0); 109 | } 110 | 111 | public StringDrawer setFront(Color front) { 112 | this.front = front; 113 | return this; 114 | } 115 | 116 | public StringDrawer setBack(Color back) { 117 | this.back = back; 118 | return this; 119 | } 120 | 121 | public void setBackgroundVisible(boolean b) { 122 | this.backgroundVisible = b; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/DefaultStringManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.eventbus.EventBus; 5 | import com.google.common.eventbus.Subscribe; 6 | import me.wener.bbvm.exception.ResourceMissingException; 7 | import me.wener.bbvm.vm.event.ResetEvent; 8 | import me.wener.bbvm.vm.event.VmTestEvent; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.inject.Inject; 13 | import javax.inject.Singleton; 14 | import java.util.Map; 15 | 16 | /** 17 | * Standard string resource implementation 18 | * 19 | * @author wener 20 | * @since 15/12/13 21 | */ 22 | @Singleton 23 | class DefaultStringManager implements StringManager { 24 | private final static Logger log = LoggerFactory.getLogger(DefaultStringManager.class); 25 | int handler = -1; 26 | // TODO Reuse handler ? 27 | Map resources = Maps.newHashMap(); 28 | 29 | @Override 30 | public StringResource getResource(int handler) { 31 | StringResource resource = resources.get(handler); 32 | if (resource == null) { 33 | throw new ResourceMissingException(getType(), handler); 34 | } 35 | return resource; 36 | } 37 | 38 | @Override 39 | public DefaultStringManager reset() { 40 | handler = -1; 41 | resources.clear(); 42 | return this; 43 | } 44 | 45 | void close(StringResource resource) { 46 | resources.remove(resource.getHandler()); 47 | } 48 | 49 | @Override 50 | public StringResource create() { 51 | log.debug("Create string resource {}", handler); 52 | StringResource resource = new StringResourceImpl(this, handler--); 53 | resources.put(resource.getHandler(), resource); 54 | return resource; 55 | } 56 | 57 | @Inject 58 | void init(EventBus eventBus) { 59 | eventBus.register(this); 60 | } 61 | 62 | @Subscribe 63 | public void onReset(ResetEvent resetEvent) { 64 | log.debug("Reset all string resources"); 65 | reset(); 66 | } 67 | 68 | @Subscribe 69 | public void onVmTest(VmTestEvent e) { 70 | log.info("On vm test handler={}, resources={}", handler, resources.size()); 71 | resources.forEach((k, v) -> log.info("#{} -> {}", k, v.getValue())); 72 | } 73 | 74 | /** 75 | * @author wener 76 | * @since 15/12/26 77 | */ 78 | static class StringResourceImpl implements StringResource { 79 | final private DefaultStringManager manager; 80 | final private int handler; 81 | private String value; 82 | 83 | public StringResourceImpl(DefaultStringManager manager, int handler) { 84 | this.manager = manager; 85 | this.handler = handler; 86 | } 87 | 88 | @Override 89 | public int getHandler() { 90 | return handler; 91 | } 92 | 93 | @Override 94 | public StringManager getManager() { 95 | return manager; 96 | } 97 | 98 | @Override 99 | public void close() { 100 | manager.close(this); 101 | } 102 | 103 | public String getValue() { 104 | return value; 105 | } 106 | 107 | public StringResourceImpl setValue(String v) { 108 | value = v; 109 | return this; 110 | } 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/VirtualMachineModule.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import com.google.common.eventbus.EventBus; 4 | import com.google.inject.AbstractModule; 5 | import com.google.inject.Module; 6 | import com.google.inject.Provides; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.inject.Named; 11 | import javax.inject.Singleton; 12 | import java.nio.charset.Charset; 13 | 14 | /** 15 | * @author wener 16 | * @since 15/12/13 17 | */ 18 | public class VirtualMachineModule extends AbstractModule { 19 | private final static Logger log = LoggerFactory.getLogger(VirtualMachineModule.class); 20 | private final VMConfig config; 21 | 22 | public VirtualMachineModule(VMConfig config) { 23 | this.config = config; 24 | } 25 | 26 | @Override 27 | protected void configure() { 28 | for (Object o : config.getModules()) { 29 | if (o instanceof Module) { 30 | install((Module) o); 31 | } else { 32 | throw new UnsupportedOperationException("Current can not handle module class"); 33 | } 34 | } 35 | // OptionalBinder.newOptionalBinder(binder(), SystemInvokeManager.class) 36 | // .setDefault().to(SystemInvokeManagerImpl.class).in(Singleton.class); 37 | 38 | bind(VM.class).in(Singleton.class); 39 | 40 | // install(MoreModules.pluggingModule(BeBasicVirtualMachine.class.getPackage().getName(), getClass().getClassLoader(), input -> { 41 | // log.info("Module {} {}", input.getKey(), config.isModuleEnabled(input.getKey()) ? "enabled" : "disabled"); 42 | // return config.isModuleEnabled(input.getKey()); 43 | // })); 44 | 45 | // Runtime charset 46 | bind(Charset.class).toInstance(config.getCharset()); 47 | } 48 | 49 | @Provides 50 | @Singleton 51 | public VMConfig config() { 52 | return config; 53 | } 54 | 55 | @Provides 56 | @Singleton 57 | public EventBus eventBus() { 58 | return new EventBus("VM"); 59 | } 60 | 61 | // region Generated Register 62 | @Named("RP") 63 | @Provides 64 | @Singleton 65 | public Register RP(VM vm) { 66 | return vm.getRegister(RegisterType.RP); 67 | } 68 | 69 | @Named("RF") 70 | @Provides 71 | @Singleton 72 | public Register RF(VM vm) { 73 | return vm.getRegister(RegisterType.RF); 74 | } 75 | 76 | @Named("RS") 77 | @Provides 78 | @Singleton 79 | public Register RS(VM vm) { 80 | return vm.getRegister(RegisterType.RS); 81 | } 82 | 83 | @Named("RB") 84 | @Provides 85 | @Singleton 86 | public Register RB(VM vm) { 87 | return vm.getRegister(RegisterType.RB); 88 | } 89 | 90 | @Named("R0") 91 | @Provides 92 | @Singleton 93 | public Register R0(VM vm) { 94 | return vm.getRegister(RegisterType.R0); 95 | } 96 | 97 | @Named("R1") 98 | @Provides 99 | @Singleton 100 | public Register R1(VM vm) { 101 | return vm.getRegister(RegisterType.R1); 102 | } 103 | 104 | @Named("R2") 105 | @Provides 106 | @Singleton 107 | public Register R2(VM vm) { 108 | return vm.getRegister(RegisterType.R2); 109 | } 110 | 111 | @Named("R3") 112 | @Provides 113 | @Singleton 114 | public Register R3(VM vm) { 115 | return vm.getRegister(RegisterType.R3); 116 | } 117 | // endregion 118 | } 119 | -------------------------------------------------------------------------------- /bbvm/std_str.go: -------------------------------------------------------------------------------- 1 | package bbvm 2 | 3 | import ( 4 | "context" 5 | "github.com/wenerme/bbvm/bbasm" 6 | "log" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | type StringHdr struct { 12 | H int 13 | V string 14 | Free bool 15 | } 16 | 17 | func (v *StringHdr) Handler() int { 18 | return v.H 19 | } 20 | 21 | func StdStringRes(rt bbasm.Runtime, std *Std) *Std { 22 | id := 0 23 | hdrs := map[int]*StringHdr{} 24 | return &Std{ 25 | AllocString: func(ctx context.Context) StringHandler { 26 | id-- 27 | hdr := &StringHdr{ 28 | H: id, 29 | } 30 | hdrs[hdr.H] = hdr 31 | return hdr 32 | }, 33 | FreeString: func(ctx context.Context, hdr StringHandler) { 34 | h := hdr.(*StringHdr) 35 | h.Free = true 36 | hdrs[h.H] = nil 37 | }, 38 | StringGet: func(ctx context.Context, hdr StringHandler) string { 39 | return hdr.(*StringHdr).V 40 | }, 41 | StringSet: func(ctx context.Context, hdr StringHandler, v string) { 42 | hdr.(*StringHdr).V = v 43 | }, 44 | StringOf: func(ctx context.Context, hdr int) StringHandler { 45 | if hdr >= 0 { 46 | return &StringHdr{ 47 | V: rt.GetString(hdr), 48 | } 49 | } 50 | h := hdrs[hdr] 51 | // handle address 52 | if h == nil { 53 | log.Println("invalid string hdr", hdr) 54 | } 55 | return h 56 | }, 57 | //StringToHandler: func(ctx context.Context, hdr StringHandler) int { 58 | // return hdr.(*StringHdr).H 59 | //}, 60 | } 61 | } 62 | func StdStringFunc(rt bbasm.Runtime, std *Std) *Std { 63 | return &Std{ 64 | StringToInt: func(ctx context.Context, hdr StringHandler) (int, error) { 65 | return strconv.Atoi(std.StringGet(ctx, hdr)) 66 | }, 67 | StringToFloat: func(ctx context.Context, hdr StringHandler) (float32, error) { 68 | v, err := strconv.ParseFloat(std.StringGet(ctx, hdr), 32) 69 | return float32(v), err 70 | }, 71 | StringCopy: func(ctx context.Context, dst StringHandler, src StringHandler) { 72 | std.StringSet(ctx, dst, std.StringGet(ctx, src)) 73 | }, 74 | StringConcat: func(ctx context.Context, a StringHandler, b StringHandler) { 75 | std.StringSet(ctx, a, std.StringGet(ctx, a)+std.StringGet(ctx, b)) 76 | }, 77 | StringLength: func(ctx context.Context, hdr StringHandler) int { 78 | return len(std.StringGet(ctx, hdr)) 79 | }, 80 | StringGetAscii: func(ctx context.Context, hdr StringHandler, idx int) int { 81 | return int(std.StringGet(ctx, hdr)[idx]) 82 | }, 83 | StringSetAscii: func(ctx context.Context, hdr StringHandler, idx, v int) { 84 | s := []byte(std.StringGet(ctx, hdr)) 85 | s[idx] = byte(v % 0xFF) 86 | std.StringSet(ctx, hdr, string(s)) 87 | }, 88 | StringCompare: func(ctx context.Context, a StringHandler, b StringHandler) int { 89 | return strings.Compare(std.StringGet(ctx, a), std.StringGet(ctx, b)) 90 | }, 91 | StringFind: func(ctx context.Context, hdr StringHandler, f StringHandler, offset int) int { 92 | s := std.StringGet(ctx, hdr) 93 | return strings.Index(s[offset:], std.StringGet(ctx, f)) 94 | }, 95 | StringLeft: func(ctx context.Context, dst StringHandler, hdr StringHandler, len int) { 96 | std.StringSet(ctx, dst, std.StringGet(ctx, hdr)[0:len]) 97 | }, 98 | StringRight: func(ctx context.Context, dst StringHandler, hdr StringHandler, l int) { 99 | s := std.StringGet(ctx, hdr) 100 | std.StringSet(ctx, dst, s[len(s)-l:]) 101 | }, 102 | StringMid: func(ctx context.Context, dst StringHandler, hdr StringHandler, idx int, len int) { 103 | s := std.StringGet(ctx, hdr) 104 | std.StringSet(ctx, dst, s[idx:len]) 105 | }, 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Gradle template 2 | .gradle 3 | build/ 4 | 5 | # Ignore Gradle GUI config 6 | gradle-app.setting 7 | 8 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 9 | !gradle-wrapper.jar 10 | ### Eclipse template 11 | *.pydevproject 12 | .metadata 13 | bin/ 14 | tmp/ 15 | *.tmp 16 | *.bak 17 | *.swp 18 | *~.nib 19 | local.properties 20 | .settings/ 21 | .loadpath 22 | 23 | # Eclipse Core 24 | .project 25 | 26 | # External tool builders 27 | .externalToolBuilders/ 28 | 29 | # Locally stored "Eclipse launch configurations" 30 | *.launch 31 | 32 | # CDT-specific 33 | .cproject 34 | 35 | # JDT-specific (Eclipse Java Development Tools) 36 | .classpath 37 | 38 | # Java annotation processor (APT) 39 | .factorypath 40 | 41 | # PDT-specific 42 | .buildpath 43 | 44 | # sbteclipse plugin 45 | .target 46 | 47 | # TeXlipse plugin 48 | .texlipse 49 | ### Maven template 50 | target/ 51 | pom.xml.tag 52 | pom.xml.releaseBackup 53 | pom.xml.versionsBackup 54 | pom.xml.next 55 | release.properties 56 | dependency-reduced-pom.xml 57 | buildNumber.properties 58 | .mvn/timing.properties 59 | ### JetBrains template 60 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 61 | 62 | *.iml 63 | 64 | ## Directory-based project format: 65 | .idea/ 66 | # if you remove the above rule, at least ignore the following: 67 | 68 | # User-specific stuff: 69 | # .idea/workspace.xml 70 | # .idea/tasks.xml 71 | # .idea/dictionaries 72 | 73 | # Sensitive or high-churn files: 74 | # .idea/dataSources.ids 75 | # .idea/dataSources.xml 76 | # .idea/sqlDataSources.xml 77 | # .idea/dynamic.xml 78 | # .idea/uiDesigner.xml 79 | 80 | # Gradle: 81 | # .idea/gradle.xml 82 | # .idea/libraries 83 | 84 | # Mongo Explorer plugin: 85 | # .idea/mongoSettings.xml 86 | 87 | ## File-based project format: 88 | *.ipr 89 | *.iws 90 | 91 | ## Plugin-specific files: 92 | 93 | # IntelliJ 94 | /out/ 95 | 96 | # mpeltonen/sbt-idea plugin 97 | .idea_modules/ 98 | 99 | # JIRA plugin 100 | atlassian-ide-plugin.xml 101 | 102 | # Crashlytics plugin (for Android Studio and IntelliJ) 103 | com_crashlytics_export_strings.xml 104 | crashlytics.properties 105 | crashlytics-build.properties 106 | ### Windows template 107 | # Windows image file caches 108 | Thumbs.db 109 | ehthumbs.db 110 | 111 | # Folder config file 112 | Desktop.ini 113 | 114 | # Recycle Bin used on file shares 115 | $RECYCLE.BIN/ 116 | 117 | # Windows Installer files 118 | *.cab 119 | *.msi 120 | *.msm 121 | *.msp 122 | 123 | # Windows shortcuts 124 | *.lnk 125 | ### OSX template 126 | .DS_Store 127 | .AppleDouble 128 | .LSOverride 129 | 130 | # Icon must end with two \r 131 | Icon 132 | 133 | # Thumbnails 134 | ._* 135 | 136 | # Files that might appear in the root of a volume 137 | .DocumentRevisions-V100 138 | .fseventsd 139 | .Spotlight-V100 140 | .TemporaryItems 141 | .Trashes 142 | .VolumeIcon.icns 143 | 144 | # Directories potentially created on remote AFP share 145 | .AppleDB 146 | .AppleDesktop 147 | Network Trash Folder 148 | Temporary Items 149 | .apdisk 150 | ### Linux template 151 | *~ 152 | 153 | # KDE directory preferences 154 | .directory 155 | 156 | # Linux trash folder which might appear on any partition or disk 157 | .Trash-* 158 | ### Java template 159 | *.class 160 | 161 | # Mobile Tools for Java (J2ME) 162 | .mtj.tmp/ 163 | 164 | # Package Files # 165 | *.jar 166 | *.war 167 | *.ear 168 | 169 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 170 | hs_err_pid* 171 | 172 | wiki 173 | ignored 174 | /bbvm-test 175 | /bbvm.wiki 176 | -------------------------------------------------------------------------------- /bbvmjs/const.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | class EnumInstance { 3 | constructor({name, value}) { 4 | this.name = name; 5 | this.value = value; 6 | } 7 | 8 | toString() { 9 | return this.name 10 | } 11 | } 12 | 13 | class EnumType { 14 | constructor(enums) { 15 | Object.assign(this, enums) 16 | } 17 | } 18 | 19 | function Enum(spec, type = EnumInstance) { 20 | let enums = Object 21 | .keys(spec) 22 | .reduce((o, k)=> { 23 | o[k] = new type({name: k, value: spec[k]}); 24 | return o 25 | }, {}); 26 | 27 | return Object.freeze(new EnumType(enums)); 28 | } 29 | 30 | /** 31 | *
 32 |  * 表示     | 字节码 | 说明
 33 |  * --------|-------|----
 34 |  * rx      | 0x0   | 寄存器寻址
 35 |  * [rx]    | 0x1   | 寄存器间接寻址
 36 |  * n       | 0x2   | 立即数寻址
 37 |  * [n]     | 0x3   | 直接寻址
 38 |  *
 39 |  * op1/op2 |rx      | [rx]   | n      | [n]
 40 |  * --------|--------|--------|--------|----
 41 |  * rx      | 0x0    | 0x1    | 0x2    | 0x3
 42 |  * [rx]    | 0x4    | 0x5    | 0x6    | 0x7
 43 |  * n       | 0x8    | 0x9    | 0xa    | 0xb
 44 |  * [n]     | 0xc    | 0xd    | 0xe    | 0xf
 45 |  */
 46 | const AddrType = Enum({
 47 |     /**
 48 |      * 寄存器寻址
 49 |      */
 50 |     REGISTER: 0,
 51 |     /**
 52 |      * 寄存器间接寻址
 53 |      */
 54 |     REGISTER_DEFERRED: 1,
 55 |     /**
 56 |      * 立即数
 57 |      */
 58 |     IMMEDIATE: 2,
 59 |     /**
 60 |      * 直接寻址
 61 |      */
 62 |     DIRECT: 3
 63 | });
 64 | 
 65 | const DataType = Enum({
 66 |     DWORD: 0,
 67 |     WORD: 1,
 68 |     BYTE: 2,
 69 |     FLOAT: 3,
 70 |     INT: 4
 71 | });
 72 | 
 73 | 
 74 | const CalcType = Enum({
 75 |     ADD: 0,
 76 |     SUB: 1,
 77 |     MUL: 2,
 78 |     DIV: 3,
 79 |     MOD: 4
 80 | });
 81 | /**
 82 |  * 
 83 |  * Z    | 0x1 | 等于
 84 |  * B    | 0x2 | Below,小于
 85 |  * BE   | 0x3 | 小于等于
 86 |  * A    | 0x4 | Above,大于
 87 |  * AE   | 0x5 | 大于等于
 88 |  * NZ   | 0x6 | 不等于
 89 |  */
 90 | const CmpType = Enum({
 91 |     Z: 1,
 92 |     B: 2,
 93 |     BE: 3,
 94 |     A: 4,
 95 |     AE: 5,
 96 |     NZ: 6,
 97 | });
 98 | const Opcode = Enum({
 99 |     NOP: 0,
100 |     LD: 1,
101 |     PUSH: 2,
102 |     POP: 3,
103 |     IN: 4,
104 |     OUT: 5,
105 |     JMP: 6,
106 |     JPC: 7,
107 |     CALL: 8,
108 |     RET: 9,
109 |     CMP: 0xA,
110 |     CAL: 0xB,
111 |     EXIT: 0xF,
112 | }, class OpcodeType extends EnumInstance {
113 |     constructor(args) {
114 |         super(args)
115 |     }
116 | 
117 |     get length() {
118 |         switch (this) {
119 |             case Opcode.NOP:
120 |             case Opcode.RET:
121 |             case Opcode.EXIT:
122 |                 return 1;
123 |             case Opcode.PUSH:
124 |             case Opcode.POP:
125 |             case Opcode.JMP:
126 |                 return 5;
127 |             case Opcode.JPC:
128 |                 return 6;
129 |             case Opcode.IN:
130 |             case Opcode.LD:
131 |             case Opcode.CMP:
132 |             case Opcode.CAL:
133 |             case Opcode.OUT:
134 |                 return 10
135 |         }
136 |     }
137 | });
138 | /**
139 |  * 寄存器类型
140 |  * 
141 |  * RP | 0x0 | 程序计数器
142 |  * RF | 0x1 | 比较标示符
143 |  * RS | 0x2 | 栈顶位置
144 |  * RB | 0x3 | 栈底位置
145 |  * R0 | 0x4 | #0 寄存器
146 |  * R1 | 0x5 | #1 寄存器
147 |  * R2 | 0x6 | #2 寄存器
148 |  * R3 | 0x7 | #3 寄存器
149 |  * 
150 | */ 151 | const RegType = Enum({ 152 | RP: 0, 153 | RF: 1, 154 | RS: 2, 155 | RB: 3, 156 | R0: 4, 157 | R1: 5, 158 | R2: 6, 159 | R3: 7, 160 | }); 161 | 162 | module.exports = { 163 | RegType, Opcode, AddrType, DataType, CalcType, CmpType 164 | }; 165 | -------------------------------------------------------------------------------- /bbasm/parser/ast.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bytes" 5 | "encoding" 6 | "fmt" 7 | ) 8 | 9 | var _ = []encoding.BinaryMarshaler{ 10 | &PseudoData{}, 11 | } 12 | 13 | type Assembly interface { 14 | SetComment(string) 15 | GetComment() string 16 | 17 | // Len Byte code length of this asm 18 | Len() int 19 | // Assembly To assembly string 20 | Assembly() string 21 | } 22 | 23 | // Symbol represent a label of a location 24 | type Symbol struct { 25 | Name string 26 | Address int 27 | Reference []func(int) // Referenced this symbol's address 28 | } 29 | 30 | func commentString(Comment string) string { 31 | if Comment == "" { 32 | return "" 33 | } 34 | return " ; " + Comment 35 | } 36 | 37 | type Comment struct { 38 | Content string 39 | Line int 40 | } 41 | 42 | func (*Comment) Len() int { 43 | return 0 44 | } 45 | func (a *Comment) Assembly() string { 46 | return "; " + a.Content 47 | } 48 | 49 | type Label struct { 50 | Name string 51 | 52 | Line int 53 | Comment string 54 | } 55 | 56 | func (a *Label) Len() int { 57 | return 0 58 | } 59 | func (a *Label) Assembly() string { 60 | return fmt.Sprintf(":%s%s", a.Name, commentString(a.Comment)) 61 | } 62 | 63 | type PseudoData struct { 64 | Label string 65 | Values []PseudoDataValue 66 | 67 | Line int 68 | Comment string 69 | } 70 | 71 | type PseudoDataValue interface { 72 | encoding.BinaryMarshaler 73 | Len() int // Byte length 74 | Assembly() string // Assembly represent 75 | } 76 | 77 | func (a *PseudoData) Len() int { 78 | n := 0 79 | for _, v := range a.Values { 80 | n += v.Len() 81 | } 82 | return n 83 | } 84 | 85 | func (a PseudoData) MarshalBinary() (data []byte, err error) { 86 | for _, v := range a.Values { 87 | b, err := v.MarshalBinary() 88 | if err != nil { 89 | return nil, err 90 | } 91 | data = append(data, b...) 92 | } 93 | return 94 | } 95 | func (a PseudoData) Assembly() string { 96 | buf := bytes.NewBufferString("DATA ") 97 | buf.WriteString(a.Label) 98 | buf.WriteRune(' ') 99 | switch len(a.Values) { 100 | case 0: 101 | // FIXME No data, what should I do 102 | case 1: 103 | buf.WriteString(a.Values[0].Assembly()) 104 | default: 105 | buf.WriteString(a.Values[0].Assembly()) 106 | for _, v := range a.Values[1:] { 107 | buf.WriteString(", ") 108 | buf.WriteString(v.Assembly()) 109 | } 110 | } 111 | 112 | buf.WriteString(commentString(a.Comment)) 113 | return buf.String() 114 | } 115 | 116 | type PseudoBlock struct { 117 | Size int 118 | Byte byte 119 | 120 | Line int 121 | Comment string 122 | } 123 | 124 | func (a *PseudoBlock) Len() int { 125 | return a.Size 126 | } 127 | func (a PseudoBlock) Assembly() string { 128 | return fmt.Sprintf(".BLOCK %v %v%s", a.Size, a.Byte, commentString(a.Comment)) 129 | } 130 | func (a *PseudoBlock) MarshalBinary() (data []byte, err error) { 131 | data = make([]byte, a.Size) 132 | for i := range data { 133 | data[i] = a.Byte 134 | } 135 | return 136 | } 137 | 138 | /* 139 | Common method 140 | */ 141 | 142 | func (a *Label) GetComment() string { 143 | return a.Comment 144 | } 145 | func (a *Label) SetComment(v string) { 146 | a.Comment = v 147 | } 148 | func (a *PseudoBlock) GetComment() string { 149 | return a.Comment 150 | } 151 | func (a *PseudoBlock) SetComment(v string) { 152 | a.Comment = v 153 | } 154 | func (a *PseudoData) GetComment() string { 155 | return a.Comment 156 | } 157 | func (a *PseudoData) SetComment(v string) { 158 | a.Comment = v 159 | } 160 | func (a *Comment) GetComment() string { 161 | return a.Content 162 | } 163 | func (a *Comment) SetComment(v string) { 164 | a.Content = v 165 | } 166 | -------------------------------------------------------------------------------- /bbasm/inst.go: -------------------------------------------------------------------------------- 1 | package bbasm 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | ) 7 | 8 | type Inst struct { 9 | DataType DataType 10 | CompareType CompareType 11 | CalculateType CalculateType 12 | Opcode Opcode 13 | A Operand 14 | B Operand 15 | 16 | Line int 17 | Comment string 18 | } 19 | 20 | func (i *Inst) Len() int { 21 | return i.Opcode.Len() 22 | } 23 | 24 | func (i *Inst) SetComment(v string) { 25 | i.Comment = v 26 | } 27 | func (i *Inst) GetComment() string { 28 | return i.Comment 29 | } 30 | func (i *Inst) MarshalBinary() ([]byte, error) { 31 | data := make([]byte, i.Opcode.Len()) 32 | data[0] = uint8(i.Opcode) << 4 33 | 34 | switch i.Opcode.Len() { 35 | case 1: // 无操作数 36 | case 5: // 一个操作数 37 | data[0] |= uint8(i.A.AddressMode) 38 | i.A.AddressMode = AddressMode(data[0] & 0xF) 39 | binary.LittleEndian.PutUint32(data[1:], uint32(i.A.V)) 40 | case 10: // 两个操作数 41 | data[0] |= uint8(i.DataType) 42 | 43 | data[1] |= uint8(i.A.AddressMode<<2 | i.B.AddressMode) 44 | binary.LittleEndian.PutUint32(data[2:], uint32(i.A.V)) 45 | binary.LittleEndian.PutUint32(data[6:], uint32(i.B.V)) 46 | 47 | if i.Opcode == CAL { 48 | data[1] |= uint8(i.CalculateType) << 4 49 | } 50 | 51 | case 6: // JPC 52 | data[0] |= uint8(i.CompareType) 53 | data[1] |= uint8(i.A.AddressMode) 54 | binary.LittleEndian.PutUint32(data[2:], uint32(i.A.V)) 55 | } 56 | return data, nil 57 | } 58 | func (i *Inst) UnmarshalBinary(data []byte) error { 59 | /* 60 | 指令码 + 数据类型 + 特殊用途字节 + 寻址方式 + 第一个操作数 + 第二个操作数 61 | 0x 0 0 0 0 00000000 00000000 62 | 63 | 无操作数 1byte 64 | 指令码 + 无用 65 | 0x 0 0 66 | 一个操作数 5byte 67 | 指令码 + 寻址方式 + 第一个操作数 68 | 0x 0 0 00000000 69 | 两个操作数 10byte 70 | 指令码 + 数据类型 + 保留字节 + 寻址方式 + 第一个操作数 + 第二个操作数 71 | 0x 0 0 0 0 00000000 00000000 72 | JPC指令 6byte 73 | 指令码 + 比较操作 + 保留字节 + 寻址方式 + 第一个操作数 74 | 0x 0 0 0 0 00000000 75 | */ 76 | i.Opcode = Opcode(data[0] >> 4) 77 | if i.Opcode.Len() > len(data) { 78 | return ErrDataToShort.New("Data is not enough for inst need %v got %v", i.Opcode.Len(), len(data)) 79 | } 80 | // clear 81 | i.A.AddressMode = 255 82 | i.B.AddressMode = 255 83 | 84 | switch i.Opcode.Len() { 85 | case 1: // 无操作数 86 | case 5: // 一个操作数 87 | i.A.AddressMode = AddressMode(data[0] & 0xF) 88 | i.A.V = int32(binary.LittleEndian.Uint32(data[1:])) 89 | case 10: // 两个操作数 90 | i.DataType = DataType(data[0] & 0xF) 91 | 92 | addrMode := data[1] & 0xF 93 | i.A.AddressMode = AddressMode(addrMode / 4) 94 | i.B.AddressMode = AddressMode(addrMode % 4) 95 | i.A.V = int32(binary.LittleEndian.Uint32(data[2:])) 96 | i.B.V = int32(binary.LittleEndian.Uint32(data[6:])) 97 | 98 | if i.Opcode == CAL { 99 | i.CalculateType = CalculateType(data[1] >> 4) 100 | } 101 | 102 | case 6: // JPC 103 | i.CompareType = CompareType(data[0] & 0xF) 104 | i.A.AddressMode = AddressMode(data[1] & 0xF) 105 | i.A.V = int32(binary.LittleEndian.Uint32(data[2:])) 106 | } 107 | return nil 108 | } 109 | 110 | func (i Inst) Assembly() (s string) { 111 | 112 | switch i.Opcode.Len() { 113 | case 1: 114 | s = fmt.Sprint(i.Opcode) 115 | case 5: 116 | s = fmt.Sprintf("%s %s", i.Opcode, i.A) 117 | case 10: 118 | switch i.Opcode { 119 | case CAL: 120 | s = fmt.Sprintf("%s %s %s %s, %s", i.Opcode, i.DataType, i.CalculateType, i.A, i.B) 121 | case LD: 122 | s = fmt.Sprintf("%s %s %s, %s", i.Opcode, i.DataType, i.A, i.B) 123 | case CMP: 124 | s = fmt.Sprintf("%s %s %s, %s", i.Opcode, i.CompareType, i.A, i.B) 125 | default: 126 | s = fmt.Sprintf("%s %s, %s", i.Opcode, i.A, i.B) 127 | } 128 | case 6: 129 | s = fmt.Sprintf("%s %s %s", i.Opcode, i.CompareType, i.A) 130 | default: 131 | panic(ErrWrongInst.New("Unknown opcode len")) 132 | } 133 | if i.Comment != "" { 134 | s += " ; " + i.Comment 135 | } 136 | return 137 | } 138 | -------------------------------------------------------------------------------- /bbasm/parser/bbasm.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/juju/errors" 5 | "github.com/wenerme/bbvm/bbasm" 6 | "math" 7 | "strings" 8 | ) 9 | 10 | func NewParser(s string) *BBAsm { 11 | return &BBAsm{Buffer: s} 12 | } 13 | 14 | type parser struct { 15 | line int 16 | stack []interface{} 17 | assemblies []Assembly 18 | } 19 | 20 | func (p *parser) Push(v interface{}) { 21 | // fmt.Printf("PUSH %#v\n", v) 22 | if v == nil { 23 | panic(errors.Errorf("Can not push nil")) 24 | } 25 | p.stack = append(p.stack, v) 26 | } 27 | func (p *parser) Pop() interface{} { 28 | if len(p.stack) == 0 { 29 | panic(errors.Errorf("Stack underflow")) 30 | } 31 | v := p.stack[len(p.stack)-1] 32 | p.stack = p.stack[:len(p.stack)-1] 33 | return v 34 | } 35 | 36 | func (p *parser) AddAssembly() Assembly { 37 | for i := len(p.stack) - 1; i >= 0; i-- { 38 | v := p.stack[i] 39 | 40 | if a, ok := v.(Assembly); ok { 41 | var e error 42 | switch a.(type) { 43 | case *bbasm.Inst: 44 | a := a.(*bbasm.Inst) 45 | //a.Line = p.line 46 | e = buildInst(a, p.stack[i+1:]...) 47 | case *Label: 48 | a := a.(*Label) 49 | //a.Line = p.line 50 | e = buildLabel(a, p.stack[i+1:]...) 51 | case *Comment: 52 | a := a.(*Comment) 53 | //a.Line = p.line 54 | e = buildComment(a, p.stack[i+1:]...) 55 | case *PseudoBlock: 56 | a := a.(*PseudoBlock) 57 | //a.Line = p.line 58 | e = buildPseudoBlock(a, p.stack[i+1:]...) 59 | case *PseudoData: 60 | a := a.(*PseudoData) 61 | e = buildPseudoData(a, p.stack[i+1:]...) 62 | } 63 | //e := build(a, p.stack[i + 1:]...) 64 | if e != nil { 65 | panic(errors.Trace(e)) 66 | } 67 | 68 | if m, ok := a.(interface { 69 | SetLine(int) 70 | }); ok { 71 | m.SetLine(p.line) 72 | } 73 | 74 | p.stack = p.stack[0:i] 75 | p.assemblies = append(p.assemblies, a) 76 | return a 77 | } 78 | } 79 | panic(errors.Errorf("No assembly avalible line %v", p.line)) 80 | } 81 | 82 | func (p *parser) AddComment() { 83 | a := p.assemblies[len(p.assemblies)-2] 84 | c := p.assemblies[len(p.assemblies)-1] 85 | // Pop Comment out 86 | p.assemblies = p.assemblies[:len(p.assemblies)-1] 87 | if m, ok := a.(interface { 88 | SetComment(string) 89 | }); ok { 90 | m.SetComment(c.(*Comment).Content) 91 | } else { 92 | panic(errors.Errorf("Can not add comment try add %#v to %#v", c, a)) 93 | } 94 | } 95 | func (p *parser) PushInst(op bbasm.Opcode) { 96 | p.Push(&bbasm.Inst{Opcode: op}) 97 | } 98 | 99 | func (p *parser) AddOperand(direct bool) { 100 | v := p.Pop() 101 | op := &bbasm.Operand{} 102 | var am bbasm.AddressMode = math.MaxUint8 103 | 104 | switch v.(type) { 105 | case string: 106 | r := Lookup(bbasm.R0, v.(string)) 107 | if r != nil { 108 | op.V = int32(r.(bbasm.RegisterType)) 109 | if direct { 110 | am = bbasm.AddressRegister 111 | } else { 112 | am = bbasm.AddressRegisterDeferred 113 | } 114 | } else { 115 | op.Symbol = v.(string) 116 | } 117 | case int: 118 | op.V = int32(v.(int)) 119 | default: 120 | panic(errors.Errorf("Can not add operand with %#v", v)) 121 | } 122 | 123 | if am == math.MaxUint8 { 124 | if direct { 125 | am = bbasm.AddressImmediate 126 | } else { 127 | am = bbasm.AddressDirect 128 | } 129 | } 130 | op.AddressMode = am 131 | p.Push(op) 132 | } 133 | 134 | func (p *parser) AddPseudoDataValue() { 135 | v := p.Pop() 136 | v, e := createPseudoDataValue(v) 137 | if e != nil { 138 | panic(errors.Trace(e)) 139 | } 140 | p.Push(v) 141 | } 142 | 143 | func (p *parser) AddInteger() { 144 | v := p.Pop() 145 | i, e := parseInt(v.(string)) 146 | if e != nil { 147 | panic(errors.Trace(e)) 148 | } 149 | p.Push(int(i)) 150 | } 151 | 152 | func lookup(t interface{}, v string) interface{} { 153 | ret := Lookup(t, strings.ToUpper(strings.Trim(v, " \t\r"))) 154 | if ret == nil { 155 | panic(errors.Errorf("Can not lookup '%v' for %T", v, t)) 156 | } 157 | return ret 158 | } 159 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingImageManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import com.google.common.collect.Sets; 6 | import com.google.common.eventbus.EventBus; 7 | import com.google.common.eventbus.Subscribe; 8 | import me.wener.bbvm.dev.ImageManager; 9 | import me.wener.bbvm.dev.ImageResource; 10 | import me.wener.bbvm.exception.ExecutionException; 11 | import me.wener.bbvm.vm.event.ResetEvent; 12 | import me.wener.bbvm.vm.event.VmTestEvent; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import javax.inject.Inject; 17 | import javax.inject.Singleton; 18 | import java.io.IOException; 19 | import java.nio.file.Files; 20 | import java.nio.file.Paths; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.NavigableSet; 24 | import java.util.Optional; 25 | 26 | /** 27 | * @author wener 28 | * @since 15/12/26 29 | */ 30 | @Singleton 31 | class SwingImageManager implements ImageManager { 32 | private final static Logger log = LoggerFactory.getLogger(ImageManager.class); 33 | private final Map resources = Maps.newConcurrentMap(); 34 | private final List directories = Lists.newArrayList("."); 35 | private final NavigableSet handlers = Sets.newTreeSet(); 36 | private int handle = 0; 37 | 38 | @Override 39 | public ImageResource load(String file, int index) { 40 | try { 41 | String fn = null; 42 | for (String directory : directories) { 43 | Optional first = Files.list(Paths.get(directory)) 44 | .map((p) -> p.getFileName().toString()) 45 | .filter((it) -> it.equalsIgnoreCase(file)) 46 | .findFirst(); 47 | if (first.isPresent()) { 48 | fn = Paths.get(directory, first.get()).toAbsolutePath().toString(); 49 | } 50 | } 51 | if (fn == null) { 52 | throw new ExecutionException(String.format("Load %s resource not found #%s %s in %s", getType(), index, file, directories)); 53 | } 54 | // Index start from 0 55 | SwingImage image = new SwingImage(nextHandler(), this, Images.read(fn, index)); 56 | image.name = index + "@" + fn; 57 | log.debug("Load {} resource #{} {}@{}", getType(), handle, index, image); 58 | resources.put(image.getHandler(), image); 59 | return image; 60 | } catch (IOException e) { 61 | throw new ExecutionException(e); 62 | } 63 | } 64 | 65 | int nextHandler() { 66 | if (handlers.isEmpty()) { 67 | return handle++; 68 | } 69 | return handlers.pollFirst(); 70 | } 71 | 72 | @Override 73 | public ImageManager reset() { 74 | resources.forEach((k, v) -> v.close()); 75 | return this; 76 | } 77 | 78 | @Override 79 | public List getResourceDirectory() { 80 | return directories; 81 | } 82 | 83 | @Override 84 | public ImageResource getResource(int handler) { 85 | return Swings.checkMissing(this, handler, resources.get(handler)); 86 | } 87 | 88 | public void close(SwingImage image) { 89 | int handler = image.getHandler(); 90 | handlers.add(handler); 91 | resources.remove(handler); 92 | } 93 | 94 | @Inject 95 | public void init(EventBus eventBus) { 96 | eventBus.register(this); 97 | } 98 | 99 | @Subscribe 100 | public void onVmTest(VmTestEvent e) { 101 | log.debug("VmTest {} loaded {}", getType(), resources.size()); 102 | resources.forEach((k, v) -> log.debug("Image #{} -> {}", k, v)); 103 | } 104 | 105 | @Subscribe 106 | public void onReset(ResetEvent e) { 107 | log.debug("Reset {} resources", getType()); 108 | reset(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/SimpleNode.java: -------------------------------------------------------------------------------- 1 | /* Generated By:JJTree: Do not edit this line. SimpleNode.java Version 6.1 */ 2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ 3 | package me.wener.bbvm.asm; 4 | 5 | public class SimpleNode extends BaseNode implements Node { 6 | 7 | protected Node parent; 8 | protected Node[] children; 9 | protected int id; 10 | protected Object value; 11 | protected BBAsmParser parser; 12 | protected Token firstToken; 13 | protected Token lastToken; 14 | 15 | public SimpleNode(int i) { 16 | id = i; 17 | } 18 | 19 | public SimpleNode(BBAsmParser p, int i) { 20 | this(i); 21 | parser = p; 22 | } 23 | 24 | public void jjtOpen() { 25 | } 26 | 27 | public void jjtClose() { 28 | } 29 | 30 | public void jjtSetParent(Node n) { 31 | parent = n; 32 | } 33 | 34 | public Node jjtGetParent() { 35 | return parent; 36 | } 37 | 38 | public void jjtAddChild(Node n, int i) { 39 | if (children == null) { 40 | children = new Node[i + 1]; 41 | } else if (i >= children.length) { 42 | Node c[] = new Node[i + 1]; 43 | System.arraycopy(children, 0, c, 0, children.length); 44 | children = c; 45 | } 46 | children[i] = n; 47 | } 48 | 49 | public Node jjtGetChild(int i) { 50 | return children[i]; 51 | } 52 | 53 | public int jjtGetNumChildren() { 54 | return (children == null) ? 0 : children.length; 55 | } 56 | 57 | public void jjtSetValue(Object value) { 58 | this.value = value; 59 | } 60 | 61 | public Object jjtGetValue() { 62 | return value; 63 | } 64 | 65 | public Token jjtGetFirstToken() { 66 | return firstToken; 67 | } 68 | 69 | public void jjtSetFirstToken(Token token) { 70 | this.firstToken = token; 71 | } 72 | 73 | public Token jjtGetLastToken() { 74 | return lastToken; 75 | } 76 | 77 | public void jjtSetLastToken(Token token) { 78 | this.lastToken = token; 79 | } 80 | 81 | /** 82 | * Accept the visitor. 83 | **/ 84 | public Object jjtAccept(BBAsmParserVisitor visitor, Object data) { 85 | return visitor.visit(this, data); 86 | } 87 | 88 | /** 89 | * Accept the visitor. 90 | **/ 91 | public Object childrenAccept(BBAsmParserVisitor visitor, Object data) { 92 | if (children != null) { 93 | for (int i = 0; i < children.length; ++i) { 94 | children[i].jjtAccept(visitor, data); 95 | } 96 | } 97 | return data; 98 | } 99 | 100 | /* You can override these two methods in subclasses of SimpleNode to 101 | customize the way the node appears when the tree is dumped. If 102 | your output uses more than one line you should override 103 | toString(String), otherwise overriding toString() is probably all 104 | you need to do. */ 105 | 106 | public String toString() { 107 | return BBAsmParserTreeConstants.jjtNodeName[id]; 108 | } 109 | 110 | public String toString(String prefix) { 111 | return prefix + toString(); 112 | } 113 | 114 | /* Override this method if you want to customize how the node dumps 115 | out its children. */ 116 | 117 | public void dump(String prefix) { 118 | System.out.println(toString(prefix)); 119 | if (children != null) { 120 | for (int i = 0; i < children.length; ++i) { 121 | SimpleNode n = (SimpleNode) children[i]; 122 | if (n != null) { 123 | n.dump(prefix + " "); 124 | } 125 | } 126 | } 127 | } 128 | 129 | public int getId() { 130 | return id; 131 | } 132 | } 133 | 134 | /* JavaCC - OriginalChecksum=cdba5246170eb8a5b058bb851eed8da4 (do not edit this line) */ 135 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/invoke/FileInvoke.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm.invoke; 2 | 3 | import me.wener.bbvm.dev.FileManager; 4 | import me.wener.bbvm.vm.Operand; 5 | import me.wener.bbvm.vm.Register; 6 | import me.wener.bbvm.vm.SystemInvoke; 7 | 8 | import javax.inject.Inject; 9 | import javax.inject.Named; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author wener 14 | * @since 15/12/17 15 | */ 16 | public class FileInvoke { 17 | private final Register r3; 18 | private final Register r2; 19 | private final Register r1; 20 | private final FileManager manager; 21 | private final int CURRENT_ADDRESS = 0x7FFFFFFF; 22 | 23 | @Inject 24 | public FileInvoke(@Named("R3") Register r3, @Named("R2") Register r2, @Named("R1") Register r1, FileManager manager) { 25 | this.r3 = r3; 26 | this.r2 = r2; 27 | this.r1 = r1; 28 | this.manager = manager; 29 | } 30 | 31 | /* 32 | 48 | 打开文件 | 0 | r0:打开方式
r1:文件号
r3:文件名字符串 | 打开方式目前只能为1 33 | 49 | 关闭文件 | 文件号 | | 34 | 50 | 从文件读取数据 | 16:读取整数 | r1:文件号
r2:位置偏移量 | r3的值变为读取的整数 35 | - | | 17:读取浮点数 | r1:文件号
r2:位置偏移量 | r3的值变为读取的浮点数 36 | - | | 18:读取字符串 | r1:文件号
r2:位置偏移量
r3:目标字符串句柄 | r3所指字符串的内容变为读取的字符串 37 | 51 | 向文件写入数据 | 16:写入整数 | r1:文件号
r2:位置偏移量
r3:整数 | 38 | - | | 17:写入浮点数 | r1:文件号
r2:位置偏移量
r3:浮点数 | 39 | - | | 18:写入字符串 | r1:文件号
r2:位置偏移量
r3:字符串 | 40 | */ 41 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 48, b = 0) 42 | public void open() throws IOException { 43 | r1.get(manager).open(r3.getString()); 44 | } 45 | 46 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 49) 47 | public void close(@Named("B") Operand b) { 48 | b.get(manager).close(); 49 | } 50 | 51 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 50, b = 16) 52 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 50, b = 17) 53 | public void readInt() throws IOException { 54 | if (r2.get() == CURRENT_ADDRESS) { 55 | r3.set(r1.get(manager).readInt()); 56 | } else { 57 | r3.set(r1.get(manager).readInt(r2.get())); 58 | } 59 | } 60 | 61 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 50, b = 18) 62 | public void readString() throws IOException { 63 | if (r2.get() == CURRENT_ADDRESS) { 64 | r3.set(r1.get(manager).readString()); 65 | } else { 66 | r3.set(r1.get(manager).readString(r2.get())); 67 | } 68 | } 69 | 70 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 51, b = 16) 71 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 51, b = 17) 72 | public void writeInt() throws IOException { 73 | if (r2.get() == CURRENT_ADDRESS) { 74 | r1.get(manager).writeInt(r3.get()); 75 | } else { 76 | r1.get(manager).writeInt(r2.get(), r3.get()); 77 | } 78 | } 79 | 80 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 51, b = 18) 81 | public void writeString() throws IOException { 82 | if (r2.get() == CURRENT_ADDRESS) { 83 | r1.get(manager).writeString(r3.getString()); 84 | } else { 85 | r1.get(manager).writeString(r2.get(), r3.getString()); 86 | } 87 | } 88 | 89 | /* 90 | 52 | 判断文件位置指针是否指向文件尾 | 0;r3为0或1 | r3:文件号 | Eof 91 | 53 | 获取文件长度 | 0 | r3:文件号,返回在 r3 | Lof 92 | 54 | 获取文件位置指针的位置 | 0;返回值在r3 | r3:文件号 | LOC(FILE) 93 | 55 | 定位文件位置指针 | 16 | r2:文件号
r3:目标位置 | 94 | */ 95 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 52) 96 | public void isEof(@Named("B") Operand b) throws IOException { 97 | r3.set(r3.get(manager).isEof() ? 1 : 0); 98 | } 99 | 100 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 53, b = 0) 101 | public void fileLength(@Named("B") Operand b) throws IOException { 102 | r3.set(r3.get(manager).length()); 103 | } 104 | 105 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 54, b = 0) 106 | public void tell() throws IOException { 107 | r3.set(r3.get(manager).tell()); 108 | } 109 | 110 | @SystemInvoke(type = SystemInvoke.Type.OUT, a = 55, b = 16) 111 | public void seek() throws IOException { 112 | r2.get(manager).seek(r3.get()); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /bbvm/instance.go: -------------------------------------------------------------------------------- 1 | package bbvm 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | "github.com/juju/errors" 7 | "github.com/wenerme/bbvm/bbasm" 8 | "go.uber.org/zap" 9 | "math" 10 | ) 11 | 12 | var _ bbasm.Runtime = &Instance{} 13 | 14 | type Instance struct { 15 | Memory []byte 16 | Order binary.ByteOrder 17 | 18 | RP bbasm.Register 19 | RF bbasm.Register 20 | RS bbasm.Register 21 | RB bbasm.Register 22 | R0 bbasm.Register 23 | R1 bbasm.Register 24 | R2 bbasm.Register 25 | R3 bbasm.Register 26 | 27 | Inst *bbasm.Inst 28 | Std *Std 29 | 30 | done bool 31 | } 32 | 33 | func (rt *Instance) GetInt(addr int) int { 34 | return int(rt.Order.Uint32(rt.Memory[addr:])) 35 | } 36 | 37 | func (rt *Instance) SetInt(addr int, val int) { 38 | rt.Order.PutUint32(rt.Memory[addr:], uint32(val)) 39 | } 40 | func (rt *Instance) GetFloat(addr int) float32 { 41 | return math.Float32frombits(uint32(rt.GetInt(addr))) 42 | } 43 | 44 | func (rt *Instance) SetFloat(addr int, val float32) { 45 | rt.SetInt(addr, int(math.Float32bits(val))) 46 | } 47 | 48 | // GetString return \0 terminated string in memory 49 | func (rt *Instance) GetString(addr int) string { 50 | l := 0 51 | slice := rt.Memory[addr:] 52 | for i, v := range slice { 53 | if v == 0 { 54 | l = i 55 | break 56 | } 57 | } 58 | s, err := rt.Std.BytesToString(slice[:l]) 59 | if err != nil { 60 | panic(err) 61 | } 62 | zap.S().Debugf("GetString %v+%v -> %v", addr, l, s) 63 | return s 64 | } 65 | func (rt *Instance) Push(val int) { 66 | rt.SetInt(rt.RS.Get(), val) 67 | rt.RS.Set(rt.RS.Get() + 4) 68 | } 69 | 70 | func (rt *Instance) Pop() int { 71 | rt.RS.Set(rt.RS.Get() - 4) 72 | return rt.GetInt(rt.RS.Get()) 73 | } 74 | 75 | func (rt *Instance) Register(registerType bbasm.RegisterType) bbasm.Register { 76 | switch registerType { 77 | case bbasm.RP: 78 | return rt.RP 79 | case bbasm.RF: 80 | return rt.RF 81 | case bbasm.RS: 82 | return rt.RS 83 | case bbasm.RB: 84 | return rt.RB 85 | case bbasm.R0: 86 | return rt.R0 87 | case bbasm.R1: 88 | return rt.R1 89 | case bbasm.R2: 90 | return rt.R2 91 | case bbasm.R3: 92 | return rt.R3 93 | } 94 | panic(errors.New("invalid " + registerType.String())) 95 | } 96 | 97 | func (rt *Instance) Jump(addr int) { 98 | rt.RP.Set(addr) 99 | } 100 | 101 | func (rt *Instance) Exit() { 102 | rt.done = true 103 | } 104 | 105 | func (rt *Instance) In(ctx context.Context, a int, b int) { 106 | rt.Std.Execute(ctx, rt, rt.Inst) 107 | } 108 | 109 | func (rt *Instance) Out(ctx context.Context, a int, b int) { 110 | rt.Std.Execute(ctx, rt, rt.Inst) 111 | } 112 | 113 | func NewInstance() *Instance { 114 | sr := &Instance{ 115 | Order: binary.LittleEndian, 116 | RP: &Register{Label: "RP"}, 117 | RF: &Register{Label: "RF"}, 118 | RS: &Register{Label: "RS"}, 119 | RB: &Register{Label: "RB"}, 120 | R0: &Register{Label: "R0"}, 121 | R1: &Register{Label: "R1"}, 122 | R2: &Register{Label: "R2"}, 123 | R3: &Register{Label: "R3"}, 124 | Inst: &bbasm.Inst{}, 125 | } 126 | sr.Inst.A.RT = sr 127 | sr.Inst.B.RT = sr 128 | return sr 129 | } 130 | 131 | func (rt *Instance) Load(rom []byte) { 132 | rt.done = false 133 | rt.Memory = make([]byte, len(rom)) 134 | copy(rt.Memory, rom) 135 | // stack 136 | rt.Memory = append(rt.Memory, make([]byte, 1024)...) 137 | rt.Reset() 138 | } 139 | 140 | func (rt *Instance) Reset() { 141 | rt.RP.Set(0) 142 | rt.RF.Set(0) 143 | rt.RB.Set(len(rt.Memory) - 1024) 144 | rt.RS.Set(rt.RB.Get()) 145 | rt.R0.Set(0) 146 | rt.R1.Set(0) 147 | rt.R2.Set(0) 148 | rt.R3.Set(0) 149 | } 150 | func (rt *Instance) Run(ctx context.Context) error { 151 | for !rt.done { 152 | if err := rt.Step(ctx); err != nil { 153 | return err 154 | } 155 | } 156 | return nil 157 | } 158 | 159 | func (rt *Instance) Step(ctx context.Context) (err error) { 160 | rp := rt.RP 161 | a := rp.Get() 162 | mem := rt.Memory 163 | if rp.Get() >= len(mem)-1024 { 164 | rt.done = true 165 | return nil 166 | } 167 | 168 | inst := rt.Inst 169 | err = inst.UnmarshalBinary(mem[rp.Get():]) 170 | if err != nil { 171 | return err 172 | } 173 | // todo return error 174 | bbasm.Execute(ctx, rt, inst) 175 | if rp.Get() == a { 176 | rp.Set(a + inst.Opcode.Len()) 177 | } 178 | return 179 | } 180 | 181 | type Register struct { 182 | V int 183 | Label string 184 | } 185 | 186 | func (sr *Register) Float() float32 { 187 | return math.Float32frombits(uint32(sr.V)) 188 | } 189 | func (sr *Register) SetFloat(v float32) { 190 | sr.V = int(math.Float32bits(v)) 191 | } 192 | func (sr *Register) Get() int { 193 | return sr.V 194 | } 195 | func (sr *Register) Set(v int) { 196 | sr.V = v 197 | } 198 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/dev/swing/SwingPageManager.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.dev.swing; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.eventbus.EventBus; 5 | import com.google.common.eventbus.Subscribe; 6 | import me.wener.bbvm.dev.PageManager; 7 | import me.wener.bbvm.dev.PageResource; 8 | import me.wener.bbvm.exception.ExecutionException; 9 | import me.wener.bbvm.exception.ResourceMissingException; 10 | import me.wener.bbvm.vm.event.ResetEvent; 11 | import me.wener.bbvm.vm.event.VmTestEvent; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import javax.imageio.ImageIO; 16 | import javax.inject.Inject; 17 | import javax.inject.Singleton; 18 | import java.io.File; 19 | import java.util.Map; 20 | 21 | import static com.google.common.base.Preconditions.checkState; 22 | 23 | /** 24 | * @author wener 25 | * @since 15/12/26 26 | */ 27 | @Singleton 28 | class SwingPageManager implements PageManager { 29 | private final static Logger log = LoggerFactory.getLogger(PageManager.class); 30 | private final Map resources = Maps.newConcurrentMap(); 31 | private int handler = 0; 32 | // TODO Need to reuse the page handler ? 33 | // private NavigableSet handlers; 34 | private int width = 240, height = 320; 35 | 36 | public SwingPageManager() { 37 | // Create a default screen 38 | SwingPage page = new SwingPage(-1, this); 39 | resources.put(-1, page); 40 | } 41 | 42 | @Override 43 | public PageManager reset() { 44 | log.debug("Reset {} resource", getType()); 45 | handler = 0; 46 | resources.forEach((k, v) -> v.close()); 47 | checkState(resources.size() == 0, "%s resources should be cleared", getType()); 48 | SwingPage page = new SwingPage(-1, this); 49 | resources.put(-1, page); 50 | return this; 51 | } 52 | 53 | @Override 54 | public PageResource create() { 55 | SwingPage page = new SwingPage(handler++, this); 56 | resources.put(page.getHandler(), page); 57 | return page; 58 | } 59 | 60 | @Override 61 | public SwingPage getScreen() { 62 | SwingPage screen = resources.get(-1); 63 | if (screen == null) { 64 | throw new ExecutionException("Screen not found, may not initialize correctly."); 65 | } 66 | return screen; 67 | } 68 | 69 | @Override 70 | public int getWidth() { 71 | return width; 72 | } 73 | 74 | @Override 75 | public int getHeight() { 76 | return height; 77 | } 78 | 79 | @Override 80 | public PageManager setSize(int w, int h) { 81 | if (w < 0 || h < 0 || w > 640 || h > 480) { 82 | throw new ExecutionException(String.format("Bad page size %s,%s", w, h)); 83 | } 84 | setSize0(w, h); 85 | return this; 86 | } 87 | 88 | private boolean setSize0(int w, int h) { 89 | if (width == w && height == h) { 90 | log.debug("{} manager size already in {},{}", getType(), w, h); 91 | return false; 92 | } else { 93 | log.info("{} set size to {},{}", getType(), w, h); 94 | // Clear all pages 95 | width = w; 96 | height = h; 97 | reset(); 98 | return true; 99 | } 100 | } 101 | 102 | @Override 103 | public PageResource getResource(int handler) { 104 | SwingPage page = resources.get(handler); 105 | if (page == null) { 106 | // log.warn("{} #{} not found", getType(), handler); 107 | throw new ResourceMissingException(getType(), handler); 108 | // return getScreen(); 109 | } 110 | return page; 111 | } 112 | 113 | public void close(SwingPage page) { 114 | resources.remove(page.getHandler()); 115 | } 116 | 117 | @Inject 118 | public void init(EventBus eventBus) { 119 | eventBus.register(this); 120 | } 121 | 122 | @Subscribe 123 | public void onVmTest(VmTestEvent e) { 124 | try { 125 | log.debug("Dump pages to file"); 126 | for (Map.Entry entry : resources.entrySet()) { 127 | String fn = "page-" + (entry.getKey() == -1 ? "screen" : entry.getKey()) + ".png"; 128 | ImageIO.write(entry.getValue().image, "png", new File(fn)); 129 | } 130 | } catch (Exception ex) { 131 | ex.printStackTrace(); 132 | } 133 | } 134 | 135 | @Subscribe 136 | public void onReset(ResetEvent e) { 137 | if (!setSize0(240, 320)) { 138 | reset(); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/Operand.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import com.google.common.base.MoreObjects; 4 | import com.google.common.base.Objects; 5 | import me.wener.bbvm.util.IsInt; 6 | 7 | import static me.wener.bbvm.util.IntEnums.fromInt; 8 | 9 | /** 10 | * @author wener 11 | * @since 15/12/10 12 | */ 13 | public class Operand implements Value { 14 | protected int value; 15 | AddressingMode addressingMode; 16 | transient VM vm; 17 | transient Symbol symbol; 18 | 19 | public Symbol getSymbol() { 20 | return symbol; 21 | } 22 | 23 | public Operand setSymbol(Symbol symbol) { 24 | this.symbol = symbol; 25 | return this; 26 | } 27 | 28 | /** 29 | * @return The interval value of this operand 30 | */ 31 | public int getInterval() { 32 | return value; 33 | } 34 | 35 | public Operand setInternal(IsInt v) { 36 | setInternal(v.asInt()); 37 | return this; 38 | } 39 | 40 | public Operand setInternal(int value) { 41 | this.value = value; 42 | return this; 43 | } 44 | 45 | public AddressingMode getAddressingMode() { 46 | return addressingMode; 47 | } 48 | 49 | public Operand setAddressingMode(AddressingMode addressingMode) { 50 | this.addressingMode = addressingMode; 51 | return this; 52 | } 53 | 54 | public VM getVm() { 55 | return vm; 56 | } 57 | 58 | public Operand setVm(VM vm) { 59 | this.vm = vm; 60 | return this; 61 | } 62 | 63 | public int get() { 64 | switch (addressingMode) { 65 | case REGISTER: 66 | return vm.getRegister(fromInt(RegisterType.class, getInterval())).get(); 67 | case REGISTER_DEFERRED: 68 | return vm.getMemory().read(vm.getRegister(fromInt(RegisterType.class, getInterval())).get()); 69 | case IMMEDIATE: 70 | return getInterval(); 71 | case DIRECT: 72 | return vm.getMemory().read(getInterval()); 73 | default: 74 | throw new AssertionError(); 75 | } 76 | } 77 | 78 | public Operand set(int v) { 79 | switch (addressingMode) { 80 | 81 | case REGISTER: 82 | vm.getRegister(fromInt(RegisterType.class, getInterval())).set(v); 83 | break; 84 | case REGISTER_DEFERRED: 85 | vm.getMemory().write(vm.getRegister(fromInt(RegisterType.class, getInterval())).get(), v); 86 | break; 87 | case IMMEDIATE: 88 | throw new AssertionError("Set a IMMEDIATE operand"); 89 | case DIRECT: 90 | vm.getMemory().write(getInterval(), v); 91 | break; 92 | default: 93 | throw new AssertionError(); 94 | } 95 | return this; 96 | } 97 | 98 | public String toAssembly() { 99 | switch (addressingMode) { 100 | case REGISTER: 101 | return String.valueOf(fromInt(RegisterType.class, getInterval())); 102 | case REGISTER_DEFERRED: 103 | return "[" + fromInt(RegisterType.class, getInterval()) + "]"; 104 | case IMMEDIATE: 105 | if ((symbol == null || symbol.getValue() != getInterval()) && vm != null) 106 | symbol = vm.getSymbol(getInterval()); 107 | return String.valueOf(symbol != null ? symbol.getName() : getInterval()); 108 | case DIRECT: 109 | if ((symbol == null || symbol.getValue() != getInterval()) && vm != null) 110 | symbol = vm.getSymbol(getInterval()); 111 | return "[" + (symbol != null ? symbol.getName() : getInterval()) + "]"; 112 | default: 113 | throw new AssertionError(); 114 | } 115 | } 116 | 117 | public void reset() { 118 | symbol = null; 119 | setInternal(0); 120 | addressingMode = null; 121 | } 122 | 123 | @Override 124 | public String toString() { 125 | return MoreObjects.toStringHelper(this) 126 | .add("value", getInterval()) 127 | .add("mode", addressingMode) 128 | .toString(); 129 | } 130 | 131 | @Override 132 | public boolean equals(Object o) { 133 | if (this == o) return true; 134 | if (!(o instanceof Operand)) return false; 135 | if (!super.equals(o)) return false; 136 | Operand operand = (Operand) o; 137 | return addressingMode == operand.addressingMode; 138 | } 139 | 140 | @Override 141 | public int hashCode() { 142 | return Objects.hashCode(super.hashCode(), addressingMode); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /bbasm/types.go: -------------------------------------------------------------------------------- 1 | package bbasm 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // go:vet 8 | 9 | type DataType uint8 10 | 11 | const ( 12 | DWORD DataType = iota 13 | WORD 14 | BYTE 15 | FLOAT 16 | INT 17 | ) 18 | 19 | func (t DataType) String() string { 20 | switch t { 21 | case DWORD: 22 | return "DWORD" 23 | case WORD: 24 | return "WORD" 25 | case BYTE: 26 | return "BYTE" 27 | case FLOAT: 28 | return "FLOAT" 29 | case INT: 30 | return "INT" 31 | } 32 | return fmt.Sprintf("DataType(%v)", uint8(t)) 33 | } 34 | 35 | type CompareType uint8 36 | 37 | const ( 38 | Z CompareType = iota + 1 // Equal 39 | B // Blow 40 | BE // Blow or Equal 41 | A // Above 42 | AE // Above or Equal 43 | NZ // Not Equal 44 | ) 45 | 46 | func (ct CompareType) IsMatch(b CompareType) bool { 47 | if ct == b { 48 | return true 49 | } 50 | switch ct { 51 | case A: 52 | { 53 | switch b { 54 | case AE, NZ: 55 | return true 56 | } 57 | } 58 | case B: 59 | { 60 | switch b { 61 | case BE, NZ: 62 | return true 63 | } 64 | } 65 | case Z: 66 | { 67 | switch b { 68 | case BE, AE: 69 | return true 70 | } 71 | } 72 | case NZ: 73 | { 74 | switch b { 75 | case B, A: 76 | return true 77 | } 78 | } 79 | case AE: 80 | { 81 | switch b { 82 | case A, Z: 83 | return true 84 | } 85 | } 86 | case BE: 87 | { 88 | switch b { 89 | case B, Z: 90 | return true 91 | } 92 | } 93 | } 94 | return false 95 | } 96 | func (ct CompareType) String() string { 97 | switch ct { 98 | case Z: 99 | return "Z" 100 | case B: 101 | return "B" 102 | case BE: 103 | return "BE" 104 | case A: 105 | return "A" 106 | case AE: 107 | return "AE" 108 | case NZ: 109 | return "NZ" 110 | } 111 | return fmt.Sprintf("CompareType(%v)", uint8(ct)) 112 | } 113 | 114 | type CalculateType uint8 115 | 116 | const ( 117 | ADD CalculateType = iota 118 | SUB 119 | MUL 120 | DIV 121 | MOD 122 | ) 123 | 124 | func (c CalculateType) String() string { 125 | switch c { 126 | case ADD: 127 | return "ADD" 128 | case SUB: 129 | return "SUB" 130 | case MUL: 131 | return "MUL" 132 | case DIV: 133 | return "DIV" 134 | case MOD: 135 | return "MOD" 136 | } 137 | return fmt.Sprintf("CalculateType(%v)", uint8(c)) 138 | } 139 | 140 | type Opcode uint8 141 | 142 | const ( 143 | NOP Opcode = iota 144 | LD 145 | PUSH 146 | POP 147 | IN 148 | OUT 149 | JMP 150 | JPC 151 | CALL 152 | RET 153 | CMP 154 | CAL 155 | EXIT Opcode = 0xF 156 | ) 157 | 158 | func (o Opcode) Len() int { 159 | switch o { 160 | case NOP, RET, EXIT: 161 | return 1 162 | case PUSH, POP, JMP, CALL: 163 | return 5 164 | case JPC: 165 | return 6 166 | case LD, IN, OUT, CMP, CAL: 167 | return 10 168 | } 169 | panic(fmt.Errorf("unexpected op(%v)", uint8(o))) 170 | } 171 | func (o Opcode) String() string { 172 | switch o { 173 | case NOP: 174 | return "NOP" 175 | case LD: 176 | return "LD" 177 | case PUSH: 178 | return "PUSH" 179 | case POP: 180 | return "POP" 181 | case IN: 182 | return "IN" 183 | case OUT: 184 | return "OUT" 185 | case JMP: 186 | return "JMP" 187 | case JPC: 188 | return "JPC" 189 | case CALL: 190 | return "CALL" 191 | case RET: 192 | return "RET" 193 | case CMP: 194 | return "CMP" 195 | case CAL: 196 | return "CAL" 197 | case EXIT: 198 | return "EXIT" 199 | } 200 | return fmt.Sprintf("Opcode(%v)", uint8(o)) 201 | } 202 | 203 | type AddressMode uint8 204 | 205 | const ( 206 | AddressRegister AddressMode = iota // 寄存器寻址 207 | AddressRegisterDeferred // 寄存器间接寻址 208 | AddressImmediate // 立即数 209 | AddressDirect // 直接寻址 210 | ) 211 | 212 | func (v AddressMode) String() string { 213 | switch v { 214 | case AddressRegister: 215 | return "Register" 216 | case AddressRegisterDeferred: 217 | return "Register Deferred" 218 | case AddressImmediate: 219 | return "Immediate" 220 | case AddressDirect: 221 | return "Direct" 222 | } 223 | return fmt.Sprintf("AddressMode(%v)", uint8(v)) 224 | } 225 | 226 | type RegisterType uint8 227 | 228 | const ( 229 | RP RegisterType = iota // 程序计数器,指令寻址寄存器 230 | RF // 标志寄存器,存储比较操作结果 231 | RS // 栈寄存器 - 空栈顶地址,指向的是下一个准备要压入数据的位置 232 | RB // 辅助栈寄存器 - 栈开始的地址(文件长度+2) 233 | R0 // #0 寄存器 234 | R1 // #1 寄存器 235 | R2 // #2 寄存器 236 | R3 // #3 寄存器 237 | ) 238 | 239 | func (r RegisterType) String() string { 240 | switch r { 241 | case RP: 242 | return "RP" 243 | case RF: 244 | return "RF" 245 | case RS: 246 | return "RS" 247 | case RB: 248 | return "RB" 249 | case R0: 250 | return "R0" 251 | case R1: 252 | return "R1" 253 | case R2: 254 | return "R2" 255 | case R3: 256 | return "R3" 257 | } 258 | return fmt.Sprintf("RegisterType(%v)", uint8(r)) 259 | } 260 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/asm/BaseBBAsmParser.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.asm; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import io.netty.buffer.ByteBuf; 6 | import me.wener.bbvm.vm.Operand; 7 | import me.wener.bbvm.vm.SymbolTable; 8 | import me.wener.bbvm.vm.Symbols; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.nio.charset.Charset; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.LinkedList; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.NavigableMap; 18 | 19 | /** 20 | * @author wener 21 | * @since 15/12/10 22 | */ 23 | class BaseBBAsmParser { 24 | protected final static Logger log = LoggerFactory.getLogger(BBAsmParser.class); 25 | protected Charset charset = StandardCharsets.UTF_8; 26 | LinkedList assemblies = Lists.newLinkedList(); 27 | Map labels = Maps.newHashMap(); 28 | NavigableMap addressTable = Maps.newTreeMap(); 29 | 30 | static String labelName(Token token) { 31 | String image = token.image; 32 | if (image.endsWith(":")) { 33 | image = image.substring(0, image.length() - 1).trim(); 34 | } 35 | return image; 36 | } 37 | 38 | public Charset getCharset() { 39 | return charset; 40 | } 41 | 42 | public BBAsmParser setCharset(Charset charset) { 43 | this.charset = charset; 44 | return (BBAsmParser) this; 45 | } 46 | 47 | void jjtreeOpenNodeScope(Node n) { 48 | } 49 | 50 | void jjtreeCloseNodeScope(Node n) { 51 | } 52 | 53 | public SymbolTable createSymbolTable() { 54 | return Symbols.table(labels.values()); 55 | } 56 | 57 | public Label addLabel(Token token) { 58 | String name = labelName(token); 59 | Label label = labels.get(name); 60 | if (label != null) { 61 | if (label.getToken() != null) 62 | throw new RuntimeException("Label already exists " + label); 63 | label.setToken(token); 64 | } else { 65 | label = new Label(name, token); 66 | } 67 | labels.put(label.name, label); 68 | assemblies.add(label); 69 | return label; 70 | } 71 | 72 | public void add(Assembly assembly) { 73 | if (assembly instanceof Label) { 74 | Label label = (Label) assembly; 75 | Label old = labels.get(label.getName()); 76 | 77 | if (old == null || old.getToken() == null) { 78 | if (old != null) { 79 | label.operands.addAll(old.operands); 80 | } 81 | labels.put(label.name, label); 82 | } else { 83 | throw new RuntimeException(String.format("Detect conflict label %s %s,%s <> %s,%s" 84 | , label.getName(), label.token.beginLine, label.token.beginColumn, old.token.beginLine, old.token.beginColumn)); 85 | } 86 | } 87 | assemblies.add(assembly); 88 | } 89 | 90 | public void addLabelOperand(Token token, Operand operand) { 91 | operand.setInternal(-1); 92 | String name = labelName(token); 93 | Label label = labels.get(name); 94 | if (label == null) { 95 | label = new Label(name); 96 | labels.put(label.name, label); 97 | } 98 | label.addOperand(token, operand); 99 | } 100 | 101 | public List getAssemblies() { 102 | return assemblies; 103 | } 104 | 105 | public void checkLabel() { 106 | // All label are addressed 107 | for (Label label : labels.values()) { 108 | if (label.getToken() == null) { 109 | throw new RuntimeException("Undefined label " + label); 110 | } 111 | if (label.value < 0) { 112 | throw new RuntimeException("Undressed label " + label); 113 | } 114 | } 115 | } 116 | 117 | public ByteBuf write(ByteBuf buf) { 118 | for (Assembly assembly : assemblies) { 119 | assembly.write(buf); 120 | } 121 | return buf; 122 | } 123 | 124 | public NavigableMap getAddressTable() { 125 | return addressTable; 126 | } 127 | 128 | /** 129 | * Will fill label address and generate address table 130 | * 131 | * @return Estimated length 132 | */ 133 | public int estimateAddress() { 134 | addressTable.clear(); 135 | int pos = 0; 136 | for (Assembly assembly : assemblies) { 137 | if (assembly instanceof Label) { 138 | ((Label) assembly).setValue(pos); 139 | } 140 | int line = assembly.getLine(); 141 | if (line >= 0) { 142 | addressTable.put(pos, line); 143 | } 144 | pos += assembly.length(); 145 | } 146 | return pos; 147 | } 148 | 149 | public void addComment(Token token, boolean isFullLine) { 150 | if (isFullLine) { 151 | assemblies.add(new Comment(token)); 152 | } else { 153 | assemblies.getLast().setComment(new Comment(token)); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /jbbvm/bbvm-core/src/main/java/me/wener/bbvm/vm/VMConfig.java: -------------------------------------------------------------------------------- 1 | package me.wener.bbvm.vm; 2 | 3 | import com.google.common.base.Predicate; 4 | import com.google.common.base.Throwables; 5 | import com.google.common.collect.Lists; 6 | import com.google.inject.Guice; 7 | import com.google.inject.Module; 8 | import com.typesafe.config.Config; 9 | import me.wener.bbvm.dev.DeviceConstants; 10 | import me.wener.bbvm.vm.invoke.InputInvoke; 11 | import me.wener.bbvm.vm.invoke.OutputInvoke; 12 | 13 | import java.nio.charset.Charset; 14 | import java.util.List; 15 | import java.util.Scanner; 16 | 17 | /** 18 | * @author wener 19 | * @since 15/12/13 20 | */ 21 | public class VMConfig { 22 | final Charset charset; 23 | final Predicate errorHandler; 24 | private final Config config; 25 | private final List invokeHandlers; 26 | private final List modules; 27 | private final int envType; 28 | 29 | private VMConfig(Builder builder) { 30 | charset = builder.charset; 31 | errorHandler = builder.errorHandler; 32 | config = builder.config; 33 | invokeHandlers = builder.invokeHandlers; 34 | modules = builder.modules; 35 | envType = builder.envType; 36 | } 37 | 38 | public static Builder newBuilder() { 39 | return new Builder(); 40 | } 41 | 42 | public List getModules() { 43 | return modules; 44 | } 45 | 46 | public List getInvokeHandlers() { 47 | return invokeHandlers; 48 | } 49 | 50 | public Charset getCharset() { 51 | return charset; 52 | } 53 | 54 | public Config getConfig() { 55 | return config; 56 | } 57 | 58 | public boolean isServiceEnabled(String name) { 59 | String path = "service." + name + ".enabled"; 60 | return config.hasPath(path) && config.getBoolean(path); 61 | } 62 | 63 | public boolean isModuleEnabled(String name) { 64 | String path = "module." + name + ".enabled"; 65 | return config.hasPath(path) && config.getBoolean(path); 66 | } 67 | 68 | public Config getModuleConfig(String name) { 69 | return null; 70 | } 71 | 72 | public Config getServiceConfig(String name) { 73 | return null; 74 | } 75 | 76 | public Predicate getErrorHandler() { 77 | return errorHandler; 78 | } 79 | 80 | public int getEnvType() { 81 | return envType; 82 | } 83 | 84 | public static final class Builder { 85 | private final List modules = Lists.newArrayList(); 86 | private int envType = DeviceConstants.ENV_SIM; 87 | private List invokeHandlers = Lists.newArrayList(); 88 | private Charset charset = Charset.forName("UTF-8"); 89 | private Predicate errorHandler = e -> { 90 | throw Throwables.propagate(e); 91 | }; 92 | private Config config; 93 | 94 | public Builder() { 95 | } 96 | 97 | public Builder(VMConfig copy) { 98 | this.charset = copy.charset; 99 | this.errorHandler = copy.errorHandler; 100 | this.config = copy.config; 101 | this.invokeHandlers = copy.invokeHandlers; 102 | } 103 | 104 | public Builder charset(Charset val) { 105 | charset = val; 106 | return this; 107 | } 108 | 109 | /** 110 | * @return Handle the exception, return true for exit 111 | */ 112 | public Builder errorHandler(Predicate val) { 113 | errorHandler = val; 114 | return this; 115 | } 116 | 117 | public Builder config(Config val) { 118 | config = val; 119 | return this; 120 | } 121 | 122 | public Builder invokeHandlers(List val) { 123 | invokeHandlers = val; 124 | return this; 125 | } 126 | 127 | public Builder envType(int val) { 128 | envType = val; 129 | return this; 130 | } 131 | 132 | public Builder withModule(Class module) { 133 | modules.add(module); 134 | return this; 135 | } 136 | 137 | public List modules() { 138 | return modules; 139 | } 140 | 141 | public Builder withModule(Module module) { 142 | modules.add(module); 143 | return this; 144 | } 145 | 146 | public Builder exitOnError() { 147 | errorHandler = e -> true; 148 | return this; 149 | } 150 | 151 | public Builder invokeWithSystemInput() { 152 | Scanner scanner = new Scanner(System.in); 153 | return invokeWith(new InputInvoke().setSupplier(scanner::nextLine)); 154 | } 155 | 156 | public Builder invokeWithSystemOutput() { 157 | return invokeWith(new OutputInvoke(System.out::print)); 158 | } 159 | 160 | public Builder invokeWith(Object handler) { 161 | invokeHandlers.add(handler); 162 | return this; 163 | } 164 | 165 | 166 | public VMConfig build() { 167 | return new VMConfig(this); 168 | } 169 | 170 | public VM create() { 171 | return Guice.createInjector(new VirtualMachineModule(build())).getInstance(VM.class); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /jbbvm/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | --------------------------------------------------------------------------------