Permalink
Browse files

support PONG

  • Loading branch information...
doodlewind committed Dec 25, 2016
1 parent a6b1920 commit 5764fa83109f99ad007f2fb9d112f55a250dcfba
Showing with 159 additions and 73 deletions.
  1. +1 −1 .gitignore
  2. +11 −40 README.md
  3. +5 −5 package.json
  4. +1 −0 pages/dist/bundle.js
  5. +11 −0 pages/index.html
  6. +17 −12 src/chip8.js
  7. +17 −0 src/entry.js
  8. +5 −0 src/index.js
  9. +14 −4 src/main.js
  10. +75 −0 src/utils/display.js
  11. +0 −8 src/utils/draw.js
  12. +2 −3 webpack.config.js
View
@@ -1,2 +1,2 @@
node_modules/
dist/
View
@@ -1,49 +1,20 @@
# es6-simple
基础 ES6 项目模板
# merry8
Chip-8 emulator for web.
## 运行
安装依赖:
## Demo
Clone this repo and open `pages/index.html` in your browser.
``` text
npm install
```
运行开发模式,将监听源文件变更:
## Development
Use `npm run dev` for dev builds and `npm run prod` for a production build.
``` text
npm run dev
```
开发模式下打包成功后,即可在另一终端窗口执行打包文件:
``` text
node dist/bundle.js
```
亦可将 `bundle.js` 通过 `<script>` 标签引入页面中,从而在浏览器环境中执行打包文件。
运行生产模式,将压缩打包文件:
``` text
npm run prod
```
## 配置
打包参数位于 `webpack.config.js` 中,默认配置如下:
### entry
采用单入口模式,将 `src/main.js` 作为入口。
### output
输出到 `dist` 目录下。
### loaders
将 JS 代码通过 babel-loader 按 ES2015 标准转译 。
To test cpu instructions, move to project root path and run `node test`.
## Changelog
* `0.0.1` TODO
* `0.1.0` Implement interpreter and GUI with basic PONG support.
## License
MIT
View
@@ -1,8 +1,8 @@
{
"name": "chip8-emu",
"description": "chip8 emulator demo",
"version": "0.0.1",
"keywords": [],
"name": "merry8",
"description": "Chip-8 emulator for web.",
"version": "0.1.0",
"keywords": ["chip-8", "emulator", "interpreter"],
"scripts": {
"dev": "webpack --watch",
"prod": "webpack -p"
@@ -15,5 +15,5 @@
"babel-preset-es2015": "^6.18.0",
"webpack": "^1.13.3"
},
"main": "app/main.js"
"main": "app/index.js"
}
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Merry8</title>
</head>
<body>
<div id="app"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
View
@@ -1,5 +1,5 @@
const getIns = require('./utils/disassembler').getIns
const draw = require('./utils/draw')
const display = require('./utils/display')
const initMem = rom => {
const mem = new Uint8Array(0xFFF)
@@ -40,7 +40,7 @@ const ops = {
// 00E0 - CLS
// Clear the display.
'00E0': (ins, c8) => {
console.log('Clear Display')
display.clear()
c8.PC += 2
return c8
},
@@ -218,23 +218,23 @@ const ops = {
// set VF = collision.
'Dxyn': (ins, c8) => {
let [, , x, y, n] = ins
c8.V[0xF] = draw(x, y, n, c8)
c8.V[0xF] = display.draw(c8.V[x], c8.V[y], n, c8)
c8.PC += 2
return c8
},
// Ex9E - SKP Vx
// Skip next instruction if key with the value of Vx is pressed.
'Ex9E': (ins, c8) => {
let [, , x] = ins
if (!c8.KEYS[c8.V[x]]) c8.PC += 4
if (c8.KEYS[c8.V[x]]) c8.PC += 4
else c8.PC += 2
return c8
},
// ExA1 - SKNP Vx
// Skip next instruction if key with the value of Vx is not pressed.
'ExA1': (ins, c8) => {
let [, , x] = ins
if (c8.KEYS[c8.V[x]]) c8.PC += 4
if (!c8.KEYS[c8.V[x]]) c8.PC += 4
else c8.PC += 2
return c8
},
@@ -320,9 +320,10 @@ const ops = {
}
}
const run = (rom, c8, speed) => {
setInterval(() => {
let loops = 100
const run = (rom, c8, conf) => {
function mainLoop () {
let loops = 5
c8.DELAY = Math.max(0, c8.DELAY - 1)
while (loops > 0) {
let ins = getIns(read(c8.MEM, c8.PC))
@@ -338,17 +339,19 @@ const run = (rom, c8, speed) => {
SP: c8.SP,
STACK: c8.STACK
})
throw 'End loop'
throw e
}
loops--
}
}, (1000 / 60) / speed)
requestAnimationFrame(mainLoop)
}
requestAnimationFrame(mainLoop)
}
module.exports = {
initMem,
ops,
load (rom) {
load (rom, conf) {
const c8 = {
MEM: initMem(rom),
V: new Uint8Array(16),
@@ -360,6 +363,8 @@ module.exports = {
DELAY: 0x00,
SOUND: 0x00
}
run(rom, c8, 1)
display.init(conf)
if (typeof window !== 'undefined') window.KEYS = c8.KEYS
run(rom, c8, conf)
}
}
View
@@ -0,0 +1,17 @@
// browser entry
const main = require('./main')
const conf = {
el: '#app',
width: 500,
speed: 1
}
const xhr = new XMLHttpRequest()
xhr.open('GET', '/roms/PONG', true)
xhr.responseType = 'arraybuffer'
xhr.onload = () => {
const rom = new Uint8Array(xhr.response)
main.load(rom, conf)
}
xhr.send()
View
@@ -0,0 +1,5 @@
// node entry
const main = require('./main')
const loader = require('./utils/loader')
loader.load('PONG').then(file => main.load(file, { speed: 1 }))
View
@@ -1,6 +1,16 @@
const loader = require('./utils/loader')
// main wrapper of core emulator
const chip8 = require('./chip8')
loader.load('PONG').then(file => {
chip8.load(file)
}).catch(e => console.log(e))
const load = (file, conf) => {
chip8.load(file, conf)
}
if (typeof window !== 'undefined') {
window.chip8 = {
load
}
}
module.exports = {
load
}
View
@@ -0,0 +1,75 @@
let _conf = {
el: '#app',
width: 500,
prefix: 'chip8'
}
let scr = Array.from({ length: 64 }, row => {
return Array.from({ length: 32 }, col => 0)
})
const color = pixel => pixel ? 'white' : 'black'
const clear = () => scr = scr.map(row => row.map(col => 0))
const renderStr = () => {
let str = '\n'
for (let j = 0; j < 32; j++) {
str += `<div class="${_conf.prefix}-row">\n`
for (let i = 0; i < 64; i++) {
str += ` <div style="background-color: ${color(scr[i][j])}"></div>\n`
}
str += '</div>\n'
}
return str
}
const init = (conf = {}) => {
if (typeof window !== 'undefined') {
_conf = Object.assign(_conf, conf)
const style = document.createElement('style')
document.querySelector(conf.el)
document.head.appendChild(style)
style.sheet.insertRule(`.${_conf.prefix}-row {
margin: auto;
display: flex;
align-items: space-between;
width: ${_conf.width}px;
height: ${_conf.width / 64}px;
}`, 0)
style.sheet.insertRule(`.${_conf.prefix}-row > div {
flex-grow: 1;
height: ${_conf.width / 64}px;
}`, 0)
document.querySelector(_conf.el).innerHTML = renderStr()
} else {
console.log('Node ENV not supported')
}
}
const draw = (x, y, n, c8) => {
const pixels = c8.MEM.filter((p, i) => i >= c8.I && i < c8.I + n)
for (let i = 0; i < 8; i++) {
for (let j = 0; j < n; j++) {
let _x = i + x > 63 ? 127 - (i + x) : (i + x)
let _y = j + y > 31 ? 63 - (j + y) : (j + y)
// HACK on offest
scr[_x - 1][_y] = scr[_x - 1][_y] ^ (pixels[j] >> (7 - i) & 1)
}
}
if (typeof window !== 'undefined') {
document.querySelector(_conf.el).innerHTML = renderStr()
} else {
console.log(`Drawing at (${x}, ${y}) with ${n} bytes`)
}
// return if collision exists
// debugger
return false
}
module.exports = {
init,
clear,
draw
}
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,10 +1,9 @@
var path = require('path')
module.exports = {
entry: './src/main.js',
target: 'node',
entry: './src/entry.js',
output: {
path: path.join(__dirname, '/dist'),
path: path.join(__dirname, '/pages/dist'),
filename: 'bundle.js'
},
module: {

0 comments on commit 5764fa8

Please sign in to comment.