> compile NEMU

ysyx_22040000 李心杨
Linux calcite 6.6.19 #1-NixOS SMP PREEMPT_DYNAMIC Fri Mar  1 12:35:11 UTC 2024 x86_64 GNU/Linux
 16:26:21  up 4 days  3:32,  2 users,  load average: 0.85, 0.91, 0.95
This commit is contained in:
tracer-ysyx 2024-03-24 16:26:21 +08:00 committed by xinyangli
parent a210694e82
commit d08c2860da
415 changed files with 44314 additions and 11 deletions

View file

@ -0,0 +1,23 @@
VIDEO_ROW = 25
VIDEO_COL = 80
AUDIO_FREQ = 44100
AUDIO_CHANNEL = 1
VIDEO_SRC = bad-apple.mp4
VIDEO = build/video.frame
AUDIO = build/audio.pcm
NAME = bad-apple
SRCS = bad-apple.c resources.S
include $(AM_HOME)/Makefile
CFLAGS += -DVIDEO_ROW=$(VIDEO_ROW) -DVIDEO_COL=$(VIDEO_COL) \
-DAUDIO_FREQ=$(AUDIO_FREQ) -DAUDIO_CHANNEL=$(AUDIO_CHANNEL)
ASFLAGS += -DVIDEO_FILE=\"$(abspath $(VIDEO))\" -DAUDIO_FILE=\"$(abspath $(AUDIO))\"
$(VIDEO):
ffmpeg -i $(VIDEO_SRC) -f image2pipe -s $(VIDEO_COL)x$(VIDEO_ROW) -vcodec rawvideo -pix_fmt monow $@
$(AUDIO):
ffmpeg -i $(VIDEO_SRC) -vn -acodec pcm_s16le -f s16le -ac $(AUDIO_CHANNEL) -ar $(AUDIO_FREQ) $@
resources.S: $(VIDEO) $(AUDIO)

View file

@ -0,0 +1,74 @@
#include <am.h>
#include <stdio.h>
#include <klib-macros.h>
#define FPS 30
#define CHAR_WHITE '.'
#define CHAR_BLACK 'X'
typedef struct {
uint8_t pixel[VIDEO_ROW * VIDEO_COL / 8];
} frame_t;
static void sleep_until(uint64_t next) {
while (io_read(AM_TIMER_UPTIME).us < next) ;
}
static uint8_t getbit(uint8_t *p, int idx) {
int byte_idx = idx / 8;
int bit_idx = idx % 8;
bit_idx = 7 - bit_idx;
uint8_t byte = p[byte_idx];
uint8_t bit = (byte >> bit_idx) & 1;
return bit;
}
int main() {
extern uint8_t video_payload, video_payload_end;
extern uint8_t audio_payload, audio_payload_end;
int audio_len = 0, audio_left = 0;
Area sbuf;
ioe_init();
frame_t *f = (void *)&video_payload;
frame_t *fend = (void *)&video_payload_end;
printf("\033[H\033[J"); // screan_clear
bool has_audio = io_read(AM_AUDIO_CONFIG).present;
if (has_audio) {
io_write(AM_AUDIO_CTRL, AUDIO_FREQ, AUDIO_CHANNEL, 1024);
audio_left = audio_len = &audio_payload_end - &audio_payload;
sbuf.start = &audio_payload;
}
uint64_t now = io_read(AM_TIMER_UPTIME).us;
for (; f < fend; f ++) {
printf("\033[0;0H"); // reset cursor
for (int y = 0; y < VIDEO_ROW; y++) {
for (int x = 0; x < VIDEO_COL; x++) {
uint8_t p = getbit(f->pixel, y * VIDEO_COL + x);
putch(p ? CHAR_BLACK : CHAR_WHITE);
}
putch('\n');
}
if (has_audio) {
int should_play = (AUDIO_FREQ / FPS) * sizeof(int16_t);
if (should_play > audio_left) should_play = audio_left;
while (should_play > 0) {
int len = (should_play > 4096 ? 4096 : should_play);
sbuf.end = sbuf.start + len;
io_write(AM_AUDIO_PLAY, sbuf);
sbuf.start += len;
should_play -= len;
}
audio_left -= should_play;
}
uint64_t next = now + (1000 * 1000 / FPS);
sleep_until(next);
now = next;
}
return 0;
}

Binary file not shown.

View file

@ -0,0 +1,12 @@
.section .data
.global video_payload, video_payload_end
.p2align 3
video_payload:
.incbin VIDEO_FILE
video_payload_end:
.global audio_payload, audio_payload_end
.p2align 3
audio_payload:
.incbin AUDIO_FILE
audio_payload_end:

View file

@ -0,0 +1,3 @@
NAME = demo
SRCS = $(shell find src -name "*.c")
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,97 @@
#ifndef __DRAW_H__
#define HAS_GUI
#include <stdio.h>
#include <am.h>
#include <amdev.h>
#include <klib-macros.h>
#define ANSI_COLOR_RED 31
#define ANSI_COLOR_GREEN 32
#define ANSI_COLOR_WHITE 37
#define ANSI_COLOR_RESET 0
#ifdef HAS_GUI
#define TILE_W 4
#define SCREEN_W 320
#define SCREEN_H 200
static inline void set_color(int c) {
}
static inline void print_char(char c, int y, int x) {
static char last_c = 0xff;
static uint32_t buf[TILE_W * TILE_W];
if (last_c != c) {
last_c = c;
uint32_t color = 0x0;
if (c != ' ') { // convert different character to different color
uint8_t r = c / 25;
c -= r * 25;
uint8_t g = c / 5;
c -= g * 5;
uint8_t b = c;
r = r * 0x100 / 5;
g = g * 0x100 / 5;
b = b * 0x100 / 5;
color = (r << 16) | (g << 8) | b;
}
int i;
for (i = 0; i < TILE_W * TILE_W; i ++) {
buf[i] = color;
}
}
io_write(AM_GPU_FBDRAW, x * TILE_W, y * TILE_W, buf, TILE_W, TILE_W, false);
}
static inline void screen_clear() {
static uint32_t buf[SCREEN_W];
int i;
for (i = 0; i < SCREEN_H; i ++) {
io_write(AM_GPU_FBDRAW, 0, i, buf, SCREEN_W, 1, false);
}
}
static inline void screen_refresh() {
io_write(AM_GPU_FBDRAW, 0, 0, NULL, 0, 0, true);
}
static inline int screen_tile_height() {
return io_read(AM_GPU_CONFIG).height / TILE_W;
}
static inline int screen_tile_width() {
return io_read(AM_GPU_CONFIG).width / TILE_W;
}
#else
static inline void set_color(int c) {
printf("\033[%dm", c);
}
static inline void print_char(char c, int y, int x) {
printf("\033[%d;%dH%c", y + 1, x + 1, c);
}
static inline void screen_clear() {
printf("\033[H\033[J");
}
static inline void screen_refresh() {
}
static inline int screen_tile_height() {
return 24;
}
static inline int screen_tile_width() {
return 80;
}
#endif
static inline void usleep(int us) {
uint64_t now = io_read(AM_TIMER_UPTIME).us;
uint64_t next = now + us;
while (io_read(AM_TIMER_UPTIME).us < next) ;
}
#endif

View file

@ -0,0 +1,219 @@
/*
* aclock - ascii clock for vt100 terminals
* failsafe mode:
* > no curses / termcap required
* > no floating point required
* > no ANSI C compiler required
*
* Copyright (c) 2002 Antoni Sawicki <tenox@tenox.tc>
* Version 1.8 (knr-nofloat-vt100); Dublin, June 2002
*
* Compilation: cc aclock-vt100.c -o aclock
*
* https://github.com/tenox7/aclock/blob/master/sources/aclock-vt100.c
*
* 2021-03-26 Meco Man port to RT-Thread
*
*/
#include <am.h>
#include <amdev.h>
#include <klib-macros.h>
#include <io.h>
static const int minute[60][8][2] = {
{ { 39,11 },{ 39,10 },{ 39,9 },{ 39,8 },{ 39,7 },{ 39,6 },{ 39,5 },{ 39,4 } },
{ { 40,11 },{ 40,10 },{ 40,9 },{ 40,8 },{ 41,7 },{ 41,6 },{ 41,5 },{ 41,4 } },
{ { 40,11 },{ 40,10 },{ 41,9 },{ 41,8 },{ 42,7 },{ 42,6 },{ 42,5 },{ 43,4 } },
{ { 40,11 },{ 41,10 },{ 41,9 },{ 42,8 },{ 43,7 },{ 43,6 },{ 44,5 },{ 44,4 } },
{ { 40,11 },{ 41,10 },{ 42,9 },{ 43,8 },{ 44,7 },{ 44,6 },{ 45,5 },{ 46,4 } },
{ { 40,11 },{ 41,10 },{ 42,9 },{ 43,8 },{ 44,7 },{ 45,6 },{ 46,5 },{ 47,5 } },
{ { 41,11 },{ 42,10 },{ 43,9 },{ 44,8 },{ 45,7 },{ 47,7 },{ 48,6 },{ 49,5 } },
{ { 41,11 },{ 42,10 },{ 44,9 },{ 45,9 },{ 46,8 },{ 48,7 },{ 49,6 },{ 50,6 } },
{ { 41,11 },{ 42,10 },{ 44,9 },{ 45,9 },{ 47,8 },{ 48,7 },{ 50,7 },{ 51,6 } },
{ { 41,11 },{ 43,10 },{ 44,10 },{ 46,9 },{ 48,9 },{ 49,8 },{ 51,7 },{ 52,7 } },
{ { 41,11 },{ 43,10 },{ 45,10 },{ 46,9 },{ 48,9 },{ 50,8 },{ 52,8 },{ 53,7 } },
{ { 41,11 },{ 43,11 },{ 45,10 },{ 47,10 },{ 49,9 },{ 50,9 },{ 52,9 },{ 54,8 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,10 },{ 49,10 },{ 51,10 },{ 53,9 },{ 55,9 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,11 },{ 49,10 },{ 51,10 },{ 53,10 },{ 55,10 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,11 },{ 49,11 },{ 51,11 },{ 53,11 },{ 55,11 } },
{ { 42,12 },{ 44,12 },{ 46,12 },{ 48,12 },{ 50,12 },{ 52,12 },{ 54,12 },{ 56,12 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,12 },{ 49,12 },{ 51,12 },{ 53,12 },{ 55,12 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,12 },{ 49,13 },{ 51,13 },{ 53,13 },{ 55,13 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,13 },{ 49,13 },{ 51,13 },{ 53,14 },{ 55,14 } },
{ { 41,12 },{ 43,12 },{ 45,13 },{ 47,13 },{ 49,14 },{ 50,14 },{ 52,14 },{ 54,15 } },
{ { 41,12 },{ 43,13 },{ 45,13 },{ 46,14 },{ 48,14 },{ 50,15 },{ 52,15 },{ 53,16 } },
{ { 41,12 },{ 43,13 },{ 44,13 },{ 46,14 },{ 48,14 },{ 49,15 },{ 51,16 },{ 52,16 } },
{ { 41,12 },{ 42,13 },{ 44,14 },{ 45,14 },{ 47,15 },{ 48,16 },{ 50,16 },{ 51,17 } },
{ { 41,12 },{ 42,13 },{ 44,14 },{ 45,14 },{ 46,15 },{ 48,16 },{ 49,17 },{ 50,17 } },
{ { 41,12 },{ 42,13 },{ 43,14 },{ 44,15 },{ 45,16 },{ 47,16 },{ 48,17 },{ 49,18 } },
{ { 40,12 },{ 41,13 },{ 42,14 },{ 43,15 },{ 44,16 },{ 45,17 },{ 46,18 },{ 47,18 } },
{ { 40,12 },{ 41,13 },{ 42,14 },{ 43,15 },{ 44,16 },{ 44,17 },{ 45,18 },{ 46,19 } },
{ { 40,12 },{ 41,13 },{ 41,14 },{ 42,15 },{ 43,16 },{ 43,17 },{ 44,18 },{ 44,19 } },
{ { 40,12 },{ 40,13 },{ 41,14 },{ 41,15 },{ 42,16 },{ 42,17 },{ 42,18 },{ 43,19 } },
{ { 40,12 },{ 40,13 },{ 40,14 },{ 40,15 },{ 41,16 },{ 41,17 },{ 41,18 },{ 41,19 } },
{ { 39,12 },{ 39,13 },{ 39,14 },{ 39,15 },{ 39,16 },{ 39,17 },{ 39,18 },{ 39,19 } },
{ { 39,12 },{ 39,13 },{ 39,14 },{ 39,15 },{ 38,16 },{ 38,17 },{ 38,18 },{ 38,19 } },
{ { 39,12 },{ 39,13 },{ 38,14 },{ 38,15 },{ 37,16 },{ 37,17 },{ 37,18 },{ 36,19 } },
{ { 39,12 },{ 38,13 },{ 38,14 },{ 37,15 },{ 36,16 },{ 36,17 },{ 35,18 },{ 35,19 } },
{ { 39,12 },{ 38,13 },{ 37,14 },{ 36,15 },{ 35,16 },{ 35,17 },{ 34,18 },{ 33,19 } },
{ { 38,12 },{ 37,13 },{ 36,14 },{ 35,15 },{ 34,16 },{ 33,17 },{ 32,18 },{ 31,18 } },
{ { 38,12 },{ 37,13 },{ 36,14 },{ 35,15 },{ 34,16 },{ 32,16 },{ 31,17 },{ 30,18 } },
{ { 38,12 },{ 37,13 },{ 35,14 },{ 34,14 },{ 33,15 },{ 31,16 },{ 30,17 },{ 29,17 } },
{ { 38,12 },{ 37,13 },{ 35,14 },{ 34,14 },{ 32,15 },{ 31,16 },{ 29,16 },{ 28,17 } },
{ { 38,12 },{ 36,13 },{ 35,13 },{ 33,14 },{ 31,14 },{ 30,15 },{ 28,16 },{ 27,16 } },
{ { 38,12 },{ 36,13 },{ 34,13 },{ 33,14 },{ 31,14 },{ 29,15 },{ 27,15 },{ 26,16 } },
{ { 38,12 },{ 36,12 },{ 34,13 },{ 32,13 },{ 30,14 },{ 29,14 },{ 27,14 },{ 25,15 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,13 },{ 30,13 },{ 28,13 },{ 26,14 },{ 24,14 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,12 },{ 30,13 },{ 28,13 },{ 26,13 },{ 24,13 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,12 },{ 30,12 },{ 28,12 },{ 26,12 },{ 24,12 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,11 },{ 28,11 },{ 26,11 },{ 24,11 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,11 },{ 28,11 },{ 26,11 },{ 24,11 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,10 },{ 28,10 },{ 26,10 },{ 24,10 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,10 },{ 30,10 },{ 28,10 },{ 26,9 },{ 24,9 } },
{ { 38,11 },{ 36,11 },{ 34,10 },{ 32,10 },{ 30,9 },{ 29,9 },{ 27,9 },{ 25,8 } },
{ { 38,11 },{ 36,11 },{ 34,10 },{ 33,10 },{ 31,9 },{ 29,9 },{ 27,8 },{ 26,8 } },
{ { 38,11 },{ 36,10 },{ 35,10 },{ 33,9 },{ 31,9 },{ 30,8 },{ 28,7 },{ 27,7 } },
{ { 38,11 },{ 37,10 },{ 35,9 },{ 34,9 },{ 32,8 },{ 31,7 },{ 29,7 },{ 28,6 } },
{ { 38,11 },{ 37,10 },{ 35,9 },{ 34,9 },{ 33,8 },{ 31,7 },{ 30,6 },{ 29,6 } },
{ { 38,11 },{ 37,10 },{ 36,9 },{ 35,8 },{ 34,7 },{ 32,7 },{ 31,6 },{ 30,5 } },
{ { 39,11 },{ 38,10 },{ 37,9 },{ 36,8 },{ 35,7 },{ 34,6 },{ 33,5 },{ 32,5 } },
{ { 39,11 },{ 38,10 },{ 37,9 },{ 36,8 },{ 35,7 },{ 35,6 },{ 34,5 },{ 33,4 } },
{ { 39,11 },{ 38,10 },{ 38,9 },{ 37,8 },{ 36,7 },{ 36,6 },{ 35,5 },{ 35,4 } },
{ { 39,11 },{ 39,10 },{ 38,9 },{ 38,8 },{ 37,7 },{ 37,6 },{ 37,5 },{ 36,4 } },
{ { 39,11 },{ 39,10 },{ 39,9 },{ 39,8 },{ 38,7 },{ 38,6 },{ 38,5 },{ 38,4 } }
};
static const int hour[60][6][2] = {
{ { 39,11 },{ 39,10 },{ 39,9 },{ 39,8 },{ 39,7 },{ 39,6 } },
{ { 40,11 },{ 40,10 },{ 40,9 },{ 40,8 },{ 41,7 },{ 41,6 } },
{ { 40,11 },{ 40,10 },{ 41,9 },{ 41,8 },{ 42,7 },{ 42,6 } },
{ { 40,11 },{ 41,10 },{ 41,9 },{ 42,8 },{ 43,7 },{ 43,6 } },
{ { 40,11 },{ 41,10 },{ 42,9 },{ 43,8 },{ 44,7 },{ 44,6 } },
{ { 40,11 },{ 41,10 },{ 42,9 },{ 43,8 },{ 44,7 },{ 45,6 } },
{ { 41,11 },{ 42,10 },{ 43,9 },{ 44,8 },{ 45,7 },{ 47,7 } },
{ { 41,11 },{ 42,10 },{ 44,9 },{ 45,9 },{ 46,8 },{ 48,7 } },
{ { 41,11 },{ 42,10 },{ 44,9 },{ 45,9 },{ 47,8 },{ 48,7 } },
{ { 41,11 },{ 43,10 },{ 44,10 },{ 46,9 },{ 48,9 },{ 49,8 } },
{ { 41,11 },{ 43,10 },{ 45,10 },{ 46,9 },{ 48,9 },{ 50,8 } },
{ { 41,11 },{ 43,11 },{ 45,10 },{ 47,10 },{ 49,9 },{ 50,9 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,10 },{ 49,10 },{ 51,10 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,11 },{ 49,10 },{ 51,10 } },
{ { 41,11 },{ 43,11 },{ 45,11 },{ 47,11 },{ 49,11 },{ 51,11 } },
{ { 42,12 },{ 44,12 },{ 46,12 },{ 48,12 },{ 50,12 },{ 52,12 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,12 },{ 49,12 },{ 51,12 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,12 },{ 49,13 },{ 51,13 } },
{ { 41,12 },{ 43,12 },{ 45,12 },{ 47,13 },{ 49,13 },{ 51,13 } },
{ { 41,12 },{ 43,12 },{ 45,13 },{ 47,13 },{ 49,14 },{ 50,14 } },
{ { 41,12 },{ 43,13 },{ 45,13 },{ 46,14 },{ 48,14 },{ 50,15 } },
{ { 41,12 },{ 43,13 },{ 44,13 },{ 46,14 },{ 48,14 },{ 49,15 } },
{ { 41,12 },{ 42,13 },{ 44,14 },{ 45,14 },{ 47,15 },{ 48,16 } },
{ { 41,12 },{ 42,13 },{ 44,14 },{ 45,14 },{ 46,15 },{ 48,16 } },
{ { 41,12 },{ 42,13 },{ 43,14 },{ 44,15 },{ 45,16 },{ 47,16 } },
{ { 40,12 },{ 41,13 },{ 42,14 },{ 43,15 },{ 44,16 },{ 45,17 } },
{ { 40,12 },{ 41,13 },{ 42,14 },{ 43,15 },{ 44,16 },{ 44,17 } },
{ { 40,12 },{ 41,13 },{ 41,14 },{ 42,15 },{ 43,16 },{ 43,17 } },
{ { 40,12 },{ 40,13 },{ 41,14 },{ 41,15 },{ 42,16 },{ 42,17 } },
{ { 40,12 },{ 40,13 },{ 40,14 },{ 40,15 },{ 41,16 },{ 41,17 } },
{ { 39,12 },{ 39,13 },{ 39,14 },{ 39,15 },{ 39,16 },{ 39,17 } },
{ { 39,12 },{ 39,13 },{ 39,14 },{ 39,15 },{ 38,16 },{ 38,17 } },
{ { 39,12 },{ 39,13 },{ 38,14 },{ 38,15 },{ 37,16 },{ 37,17 } },
{ { 39,12 },{ 38,13 },{ 38,14 },{ 37,15 },{ 36,16 },{ 36,17 } },
{ { 39,12 },{ 38,13 },{ 37,14 },{ 36,15 },{ 35,16 },{ 35,17 } },
{ { 38,12 },{ 37,13 },{ 36,14 },{ 35,15 },{ 34,16 },{ 33,17 } },
{ { 38,12 },{ 37,13 },{ 36,14 },{ 35,15 },{ 34,16 },{ 32,16 } },
{ { 38,12 },{ 37,13 },{ 35,14 },{ 34,14 },{ 33,15 },{ 31,16 } },
{ { 38,12 },{ 37,13 },{ 35,14 },{ 34,14 },{ 32,15 },{ 31,16 } },
{ { 38,12 },{ 36,13 },{ 35,13 },{ 33,14 },{ 31,14 },{ 30,15 } },
{ { 38,12 },{ 36,13 },{ 34,13 },{ 33,14 },{ 31,14 },{ 29,15 } },
{ { 38,12 },{ 36,12 },{ 34,13 },{ 32,13 },{ 30,14 },{ 29,14 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,13 },{ 30,13 },{ 28,13 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,12 },{ 30,13 },{ 28,13 } },
{ { 38,12 },{ 36,12 },{ 34,12 },{ 32,12 },{ 30,12 },{ 28,12 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,11 },{ 28,11 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,11 },{ 28,11 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,11 },{ 30,10 },{ 28,10 } },
{ { 38,11 },{ 36,11 },{ 34,11 },{ 32,10 },{ 30,10 },{ 28,10 } },
{ { 38,11 },{ 36,11 },{ 34,10 },{ 32,10 },{ 30,9 },{ 29,9 } },
{ { 38,11 },{ 36,11 },{ 34,10 },{ 33,10 },{ 31,9 },{ 29,9 } },
{ { 38,11 },{ 36,10 },{ 35,10 },{ 33,9 },{ 31,9 },{ 30,8 } },
{ { 38,11 },{ 37,10 },{ 35,9 },{ 34,9 },{ 32,8 },{ 31,7 } },
{ { 38,11 },{ 37,10 },{ 35,9 },{ 34,9 },{ 33,8 },{ 31,7 } },
{ { 38,11 },{ 37,10 },{ 36,9 },{ 35,8 },{ 34,7 },{ 32,7 } },
{ { 39,11 },{ 38,10 },{ 37,9 },{ 36,8 },{ 35,7 },{ 34,6 } },
{ { 39,11 },{ 38,10 },{ 37,9 },{ 36,8 },{ 35,7 },{ 35,6 } },
{ { 39,11 },{ 38,10 },{ 38,9 },{ 37,8 },{ 36,7 },{ 36,6 } },
{ { 39,11 },{ 39,10 },{ 38,9 },{ 38,8 },{ 37,7 },{ 37,6 } },
{ { 39,11 },{ 39,10 },{ 39,9 },{ 39,8 },{ 38,7 },{ 38,6 } }
};
static const int circle[60][3] = {
{ 62,12,111 }, { 61,13,46 }, { 61,14,46 }, { 60,15,46 },
{ 60,16,46 }, { 59,17,111 }, { 57,18,46 }, { 56,19,46 },
{ 54,20,46 }, { 52,20,46 }, { 51,21,111 }, { 48,22,46 },
{ 46,22,46 }, { 44,22,46 }, { 42,22,46 }, { 40,23,111 },
{ 37,22,46 }, { 35,22,46 }, { 33,22,46 }, { 31,22,46 },
{ 29,21,111 }, { 27,20,46 }, { 25,20,46 }, { 23,19,46 },
{ 22,18,46 }, { 20,17,111 }, { 19,16,46 }, { 19,15,46 },
{ 18,14,46 }, { 18,13,46 }, { 18,12,111 }, { 18,10,46 },
{ 18,9,46 }, { 19,8,46 }, { 19,7,46 }, { 20,6,111 },
{ 22,5,46 }, { 23,4,46 }, { 25,3,46 }, { 27,3,46 },
{ 28,2,111 }, { 31,1,46 }, { 33,1,46 }, { 35,1,46 },
{ 37,1,46 }, { 39,1,111 }, { 42,1,46 }, { 44,1,46 },
{ 46,1,46 }, { 48,1,46 }, { 51,2,111 }, { 52,3,46 },
{ 54,3,46 }, { 56,4,46 }, { 57,5,46 }, { 59,6,111 },
{ 60,7,46 }, { 60,8,46 }, { 61,9,46 }, { 61,10,46 }
};
static void draw_point(int x, int y, int c) {
int xx = x - 16;
#ifdef HAS_GUI
xx /= 2;
#endif
print_char(c, y, xx);
}
//void draw_text(int x, int y, char *string) {
// rt_kprintf("\033[%d;%dH%s", y, x, string);
//}
static void draw_circle(void) {
int n;
for(n=0;n<60;n++)
draw_point(circle[n][0], circle[n][1], circle[n][2]);
}
static void draw_hour(int n) {
int m;
for(m=0;m<6;m++)
draw_point(hour[n][m][0], hour[n][m][1], 'h');
}
static void draw_minute(int n) {
int m;
for(m=0;m<8;m++)
draw_point(minute[n][m][0], minute[n][m][1], 'M');
}
static void draw_seconds(int n) {
int m;
for(m=0;m<8;m++)
draw_point(minute[n][m][0], minute[n][m][1], '.');
}
void aclock(void) {
while(1) {
AM_TIMER_RTC_T rtc = io_read(AM_TIMER_RTC);
screen_clear();
draw_circle();
draw_hour(((rtc.hour > 12 ? rtc.hour - 12 : rtc.hour) * 5) + (rtc.minute / 10));
draw_minute(rtc.minute);
draw_seconds(rtc.second);
screen_refresh();
//draw_text(35, 6, ".:ACLOCK:.");
//rt_sprintf(digital_time, "[%02d:%02d:%02d]", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
//draw_text(35, 19, digital_time);
usleep(1000000);
}
}

View file

@ -0,0 +1,70 @@
/* from http://rosettacode.org/wiki/Langton%27s_ant#C */
#include <stdlib.h>
#include <string.h>
#include <io.h>
static int w = 40, h = 25;
static unsigned char *pix = NULL;
static void refresh(int x, int y) {
int i, j, k;
screen_clear();
for (i = k = 0; i < h; i++)
for (j = 0; j < w; j++, k++)
print_char(pix[k] ? '#' : ' ', i, j);
}
void ant() {
w = screen_tile_width();
h = screen_tile_height();
int dx = 0, dy = 1, i, k;
int x = w / 2, y = h / 2;
pix = malloc(w * h);
memset(pix, 0, w * h);
screen_clear();
while (1) {
i = (y * w + x);
if (pix[i]) k = dx, dx = -dy, dy = k;
else k = dy, dy = -dx, dx = k;
pix[i] = !pix[i];
print_char(pix[i] ? 'o' : ' ', y + 1, x + 1);
x += dx, y += dy;
k = 0;
if (x < 0) {
memmove(pix + 1, pix, w * h - 1);
for (i = 0; i < w * h; i += w) pix[i] = 0;
x++, k = 1;
}
else if (x >= w) {
memmove(pix, pix + 1, w * h - 1);
for (i = w-1; i < w * h; i += w) pix[i] = 0;
x--, k = 1;
}
if (y >= h) {
memmove(pix, pix + w, w * (h - 1));
memset(pix + w * (h - 1), 0, w);
y--, k = 1;
}
else if (y < 0) {
memmove(pix + w, pix, w * (h - 1));
memset(pix, 0, w);
y++, k = 1;
}
if (k) refresh(x, y);
set_color(ANSI_COLOR_RED);
print_char('+', y + 1, x + 1);
set_color(ANSI_COLOR_RESET);
screen_refresh();
usleep(10000);
}
}

View file

@ -0,0 +1,98 @@
/* from http://rosettacode.org/wiki/Execute_Brain****#C */
/* This is the Neutron brainfuck interpreter.
* It's rather small and dense, but still readable, more or less.
*
* Robert de Bath -- 2013.
*/
#include <am.h>
#include <klib.h>
#include <io.h>
static const char *prog =
#include "mandelbrot.h"
;
struct bfi { char cmd; struct bfi *next, *jmp; };
struct mem { char val; struct mem *next, *prev; };
static inline void putch2(char c) {
static int x = 0, y = 0;
if (c == '\n') {
y ++;
x = 0;
} else {
if (x % 2 == 0) {
print_char(c, y, x / 2);
screen_refresh();
}
x ++;
}
}
void bf() {
int ch;
struct bfi *p=0, *n=0, *j=0, *pgm = 0;
struct mem *m = malloc(sizeof(*m));
memset(m, 0, sizeof(*m));
screen_clear();
/*
* For each character, if it's a valid BF command add it onto the
* end of the program. If the input is stdin use the '!' character
* to mark the end of the program and the start of the data, but
* only if we have a complete program. The 'j' variable points
* at the list of currently open '[' commands, one is matched off
* by each ']'. A ']' without a matching '[' is not a legal BF
* command and so is ignored. If there are any '[' commands left
* over at the end they are not valid BF commands and so are ignored.
*/
const char *s = prog;
while((ch = *(s ++)) != '\0') {
if (ch == '<' || ch == '>' || ch == '+' || ch == '-' ||
ch == ',' || ch == '.' || ch == '[' || (ch == ']' && j)) {
if ((n = malloc(sizeof(*n))) == NULL) {
printf("malloc failed! exiting...\n");
halt(1);
}
memset(n, 0, sizeof(*n));
if (p) p->next = n; else pgm = n;
n->cmd = ch; p = n;
if (n->cmd == '[') { n->jmp=j; j = n; }
else if (n->cmd == ']') {
n->jmp = j; j = j->jmp; n->jmp->jmp = n;
}
}
}
/* Ignore any left over '[' commands */
while(j) { p = j; j = j->jmp; p->jmp = 0; p->cmd = ' '; }
/* Execute the loaded BF program */
for(n=pgm; n; n=n->next) {
switch(n->cmd) {
case '+': m->val++; break;
case '-': m->val--; break;
case '.': putch2(m->val); break;
case ',': if((ch=*(s ++))!='\0') m->val=ch; break;
case '[': if (m->val == 0) n=n->jmp; break;
case ']': if (m->val != 0) n=n->jmp; break;
case '<':
if (!(m=m->prev)) {
printf("Hit start of tape\n");
halt(1);
}
break;
case '>':
if (m->next == 0) {
if ((m->next = malloc(sizeof(*m))) == NULL) {
printf("malloc failed! exiting...\n");
halt(1);
}
memset(m->next, 0, sizeof(*m));
m->next->prev = m;
}
m=m->next;
break;
}
}
}

View file

@ -0,0 +1,146 @@
"\
A mandelbrot set fractal viewer in brainf*** written by Erik Bosman \
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[ \
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+ \
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>> \
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>> \
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>> \
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>> \
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>> \
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<< \
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[ \
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[ \
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[ \
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<< \
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<< \
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>> \
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+ \
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>> \
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<< \
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<< \
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>> \
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> \
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<< \
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<< \
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[-> \
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<< \
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++ \
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>- \
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>> \
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<< \
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[- \
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<< \
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]< \
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>> \
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>> \
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-< \
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>> \
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+ \
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> \
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- \
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> \
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+> \
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++ \
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+ \
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[ \
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-< \
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<< \
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-] \
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<< \
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<< \
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<< \
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<< \
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<< \
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<< \
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<< \
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<< \
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<< \
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<< \
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<< \
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-< \
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[ \
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+ \
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->> \
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<< \
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[ \
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[ \
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]> \
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<< \
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<< \
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[- \
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>> \
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>> \
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<< \
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]> \
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>> \
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>> \
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<< \
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<< \
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>> \
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<< \
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<< \
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]< \
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]< \
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+ \
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>- \
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<< \
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+> \
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>- \
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[ \
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>> \
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>> \
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<< \
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<< \
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+ \
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>> \
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> \
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>> \
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+ \
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> \
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- \
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> \
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<< \
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>> \
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>> \
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+ \
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>> \
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>> \
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<] \
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<< \
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+< \
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]> \
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<< \
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[ \
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<< \
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<< \
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<< \
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<< \
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>> \
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<< \
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]< \
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>> \
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<< \
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<< \
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<< \
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-< \
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<< \
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<< \
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<< \
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>> \
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<< \
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>> \
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<< \
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>> \
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<- \
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<< \
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>> \
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<< \
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>> \
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+< \
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<< \
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>> \
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>> \
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++ \
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<< \
<<<<<]]>>>]"

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Fontaine Hugo a.k.a "Usiten"
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,72 @@
/************************************************************************
The Matrix Rain Screen Saver
This code is converted from QBASIC to C.
QBasic Code from
http://codegolf.stackexchange.com/questions/17285/make-the-matrix-digital-rain-using-the-shortest-amount-of-code
************************************************************************/
#include <stdlib.h>
#include <am.h>
#include <io.h>
#define W 80
#define H 24
static int t[W];
static void sub_d(int p, int s, int x, int y) {
uint8_t r = (p % 16) * 16;
uint8_t g = 180 - p;
if (r < 10) {
// set_color(ANSI_COLOR_RESET);
}
else {
if (g > 170) {
set_color(ANSI_COLOR_WHITE);
}
else if (g < 170) {
set_color(ANSI_COLOR_GREEN);
}
}
if ((y >= 0) && (y < H) && (x < W)) {
char c = (r < 10 ? ' ' : 33 + (x * y) % 94);
print_char(c, y, x);
//)vt_draw_char_at(y, x, c);
}
}
void cmatrix() {
int i, x, y, k;
screen_clear();
x = rand();
for (i = 0; i < W; i++) {
t[i] = - rand() % 50;
}
sub_d(1,1,10,10);
while (1) {
for (k = 1; k < W; k++) {
i = rand() % (W-1);
if (t[i] > 28)t[i] = 0;
t[i] = t[i] + 1;
y = t[i];
sub_d( 0 , 0, i, y - 6);
sub_d( 2 + x, 0, i, y - 5);
sub_d( 2 + x, 0, i, y - 4);
sub_d( 10 + x, 0, i, y - 3);
sub_d( 10 + x, 0, i, y - 2);
sub_d( 11 + x, 0, i, y - 1);
sub_d( 0 , 2 + x, i, y);
}
screen_refresh();
usleep(100000);
}
}

View file

@ -0,0 +1,82 @@
/**
* Original author:
* https://twitter.com/a1k0n
* https://www.a1k0n.net/2021/01/13/optimizing-donut.html
*
* Change Logs:
* Date Author Notes
* 2006-09-15 Andy Sloane First version
* 2011-07-20 Andy Sloane Second version
* 2021-01-13 Andy Sloane Third version
* 2021-03-25 Meco Man Port to RT-Thread RTOS
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#define R(mul,shift,x,y) \
_=x; \
x -= mul*y>>shift; \
y += mul*_>>shift; \
_ = (3145728-x*x-y*y)>>11; \
x = x*_>>10; \
y = y*_>>10;
static char b[1760];
static signed char z[1760];
void donut(void) {
int sA = 1024, cA = 0, sB = 1024, cB = 0, _;
while(1) {
memset(b, 32, 1760); // text buffer
memset(z, 127, 1760); // z buffer
int sj = 0, cj = 1024;
for (int j = 0; j < 90; j++) {
int si = 0, ci = 1024; // sine and cosine of angle i
for (int i = 0; i < 324; i++) {
int R1 = 1, R2 = 2048, K2 = 5120*1024;
int x0 = R1*cj + R2,
x1 = ci*x0 >> 10,
x2 = cA*sj >> 10,
x3 = si*x0 >> 10,
x4 = R1*x2 - (sA*x3 >> 10),
x5 = sA*sj >> 10,
x6 = K2 + R1*1024*x5 + cA*x3,
x7 = cj*si >> 10,
x = 25 + 30*(cB*x1 - sB*x4)/x6,
y = 12 + 15*(cB*x4 + sB*x1)/x6,
N = (((-cA*x7 - cB*((-sA*x7>>10) + x2) - ci*(cj*sB >> 10)) >> 10) - x5) >> 7;
int o = x + 80 * y;
signed char zz = (x6-K2)>>15;
if (22 > y && y > 0 && x > 0 && 80 > x && zz < z[o]) {
z[o] = zz;
b[o] = ".,-~:;=!*#$@"[N > 0 ? N : 0];
}
R(5, 8, ci, si) // rotate i
}
R(9, 7, cj, sj) // rotate j
}
R(5, 7, cA, sA);
R(5, 8, cB, sB);
screen_clear();
int y = 0, x = 0;
for (int k = 0; 1761 > k; k++) {
if (k % 80) {
if (x < 50) print_char(b[k], y, x);
x ++;
} else {
y ++;
x = 1;
}
}
screen_refresh();
usleep(100000);
}
}

View file

@ -0,0 +1,96 @@
/* from http://rosettacode.org/wiki/Galton_box_animation#C */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#define BALLS 1024
#define N 8
#define W (N * 2 + 1)
#define H_MAX 50
#define H_MIN 30
static int h = 0;
static int *x = NULL, *y = NULL, cnt = 0;
static char *b = NULL;
#define B(y, x) b[(y)*W + x]
#define C(y, x) ' ' == b[(y)*W + x]
#define V(i) B(y[i], x[i])
static int rnd(int a) { return rand() % a; }
static void show_board() {
int i, j;
for (i = 0; i < h; i++)
for (j = 0; j < W; j++) {
if (B(i, j) == '*') {
set_color(C(i - 1, j) ? ANSI_COLOR_GREEN : ANSI_COLOR_RED);
print_char(B(i, j), i, 2 * j);
set_color(ANSI_COLOR_RESET);
} else {
print_char(B(i, j), i, 2 * j);
}
print_char(' ', i, 2 * j + 1);
}
screen_refresh();
}
static void init() {
int i, j;
screen_clear();
b = malloc(W * h);
memset(b, ' ', W * h);
x = malloc(sizeof(int) * BALLS * 2);
y = x + BALLS;
for (i = 0; i < N; i++)
for (j = -i; j <= i; j += 2)
B(2 * i+2, j + W/2) = '*';
}
static void move(int idx) {
int xx = x[idx], yy = y[idx], c, kill = 0, sl = 3, o = 0;
if (yy < 0) return;
if (yy == h - 1) { y[idx] = -1; return; }
switch(c = B(yy + 1, xx)) {
case ' ': yy++; break;
case '*': sl = 1;
default: if (xx < W - 1 && C(yy, xx + 1) && C(yy + 1, xx + 1))
if (!rnd(sl++)) o = 1;
if (xx && C(yy, xx - 1) && C(yy + 1, xx - 1))
if (!rnd(sl++)) o = -1;
if (!o) kill = 1;
xx += o;
}
c = V(idx); V(idx) = ' ';
idx[y] = yy, idx[x] = xx;
B(yy, xx) = c;
if (kill) idx[y] = -1;
}
static int run(void) {
static int step = 0;
int i;
for (i = 0; i < cnt; i++) move(i);
if (2 == ++step && cnt < BALLS) {
step = 0;
x[cnt] = W/2;
y[cnt] = 0;
if (V(cnt) != ' ') return 0;
V(cnt) = rnd(80) + 43;
cnt++;
}
return 1;
}
void galton() {
h = screen_tile_height() - 2;
if (h > H_MAX) h = H_MAX;
if (h < H_MIN) h = H_MIN;
init();
do { show_board(), usleep(6000); } while (run());
}

View file

@ -0,0 +1,60 @@
/* from http://rosettacode.org/wiki/Towers_of_Hanoi#C */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#define H 7
typedef struct { int *x, n; } tower;
static tower *new_tower(int cap) {
int size = sizeof(tower) + sizeof(int) * cap;
tower *t = malloc(size);
memset(t, 0, size);
t->x = (int*)(t + 1);
return t;
}
static tower *t[3];
static void text(int y, int i, int d, const char *s) {
int yy = H - y + 1;
int xx = (H + 1) * (2 * i + 1) - d;
while (d--) {
for (const char *p = s; *p; p ++) {
print_char(*p, yy, xx ++);
}
}
}
static void add_disk(int i, int d) {
t[i]->x[t[i]->n++] = d;
text(t[i]->n, i, d, "==");
screen_refresh();
usleep(100000);
}
int remove_disk(int i) {
int d = t[i]->x[--t[i]->n];
text(t[i]->n + 1, i, d, " ");
return d;
}
void move(int n, int from, int to, int via) {
if (!n) return;
move(n - 1, from, via, to);
add_disk(to, remove_disk(from));
move(n - 1, via, to, from);
}
void hanoi() {
screen_clear();
int c;
for (c = 0; c < 3; c++) t[c] = new_tower(H);
for (c = H; c; c--) add_disk(0, c);
move(H, 0, 2, 1);
}

View file

@ -0,0 +1,56 @@
/* adapted from http://rosettacode.org/wiki/Conway%27s_Game_of_Life */
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
static int w = 40, h = 25;
static unsigned *new_array = NULL;
static unsigned *univ_array = NULL;
void show(void *u) {
int x,y;
int (*univ)[w] = u;
screen_clear();
for (y=0;y<h;y++) {
for (x=0;x<w;x++)
print_char(univ[y][x] ? 'o' : ' ', y, x);
}
screen_refresh();
}
void evolve(void *u) {
int x,y,x1,y1;
unsigned (*univ)[w] = u;
unsigned (*new)[w] = (void *)new_array;
for (y=0;y<h;y++) for (x=0;x<w;x++) {
int n = 0;
for (y1 = y - 1; y1 <= y + 1; y1++)
for (x1 = x - 1; x1 <= x + 1; x1++)
if (univ[(y1 + h) % h][(x1 + w) % w])
n++;
if (univ[y][x]) n--;
new[y][x] = (n == 3 || (n == 2 && univ[y][x]));
}
for (y=0;y<h;y++) for (x=0;x<w;x++) univ[y][x] = new[y][x];
}
void game_of_life(void) {
w = screen_tile_width();
h = screen_tile_height();
univ_array = malloc(h * w * sizeof(unsigned));
new_array = malloc(h * w * sizeof(unsigned));
unsigned (*univ)[w] = (void *)univ_array;
int x,y;
for (x=0;x<w;x++)
for (y=0;y<h;y++)
univ[y][x] = rand() % 2;
while (1) {
show(univ);
evolve(univ);
usleep(200000);
}
}

View file

@ -0,0 +1,44 @@
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
void ant();
void galton();
void hanoi();
void game_of_life();
void aclock();
void cmatrix();
void donut();
void bf();
int main(const char *args) {
ioe_init();
switch (args[0]) {
case '1': ant(); break;
case '2': galton(); break;
case '3': hanoi(); break;
case '4': game_of_life(); break;
case '5': aclock(); break;
case '6': cmatrix(); break;
case '7': donut(); break;
case '8': bf(); break;
default:
printf("Usage: make run mainargs=*\n");
printf(" 1: ant\n");
printf(" 2: galton\n");
printf(" 3: hanoi\n");
printf(" 4: game of life\n");
printf(" 5: aclock\n");
printf(" 6: cmatrix\n");
printf(" 7: donut\n");
printf(" 8: bf\n");
}
printf("Press Q to Exit\n");
while (1) {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
if (ev.keydown && ev.keycode == AM_KEY_Q) break;
}
return 0;
}

View file

@ -0,0 +1,3 @@
NAME = hello
SRCS = hello.c
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,13 @@
#include <am.h>
#include <klib-macros.h>
int main(const char *args) {
const char *fmt =
"Hello, AbstractMachine!\n"
"mainargs = '%'.\n";
for (const char *p = fmt; *p; p++) {
(*p == '%') ? putstr(args) : putch(*p);
}
return 0;
}

View file

@ -0,0 +1,3 @@
NAME = litenes
SRCS = $(shell find src/ -name "*.c")
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,2 @@
This is the AbstractMachine port of mynes (https://github.com/yaglo/mynes).
Emulates "Super Mario Bros" on NES (CPU, PPU, and peripherals).

View file

@ -0,0 +1,16 @@
#include "common.h"
bool common_bit_set(long long value, byte position) { return value & (1L << position); }
// I could do this through non-void methods with returns in one copy,
// but this variant is slightly faster, and needs less typing in client code
#define M_common(SUFFIX, TYPE) \
void common_set_bit##SUFFIX(TYPE *variable, byte position) { *variable |= 1L << position; } \
void common_unset_bit##SUFFIX(TYPE *variable, byte position) { *variable &= ~(1L << position); } \
void common_toggle_bit##SUFFIX(TYPE *variable, byte position) { *variable ^= 1L << position; } \
void common_modify_bit##SUFFIX(TYPE *variable, byte position, bool set) \
{ set ? common_set_bit##SUFFIX(variable, position) : common_unset_bit##SUFFIX(variable, position); }
M_common(b, byte)
M_common(w, word)
M_common(d, dword)

View file

@ -0,0 +1,33 @@
#ifndef COMMON_H
#define COMMON_H
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
typedef uint8_t byte;
typedef uint16_t word;
typedef uint32_t dword;
// Binary Operations
bool common_bit_set(long long value, byte position);
// Byte Bit Operations
void common_set_bitb(byte *variable, byte position);
void common_unset_bitb(byte *variable, byte position);
void common_toggle_bitb(byte *variable, byte position);
void common_modify_bitb(byte *variable, byte position, bool set);
// Word Bit Operations
void common_set_bitw(word *variable, byte position);
void common_unset_bitw(word *variable, byte position);
void common_toggle_bitw(word *variable, byte position);
void common_modify_bitw(word *variable, byte position, bool set);
// Double Word Bit Operations
void common_set_bitd(dword *variable, byte position);
void common_unset_bitd(dword *variable, byte position);
void common_toggle_bitd(dword *variable, byte position);
void common_modify_bitd(dword *variable, byte position, bool set);
#endif

View file

@ -0,0 +1,101 @@
#include "cpu.h"
#include "cpu-internal.h"
#include "memory.h"
// CPU Addressing Modes
void cpu_address_implied() { }
void cpu_address_immediate() {
op_value = memory_readb(cpu.PC);
cpu.PC++;
}
void cpu_address_zero_page() {
op_address = memory_readb(cpu.PC);
op_value = CPU_RAM[op_address];
cpu.PC++;
}
void cpu_address_zero_page_x() {
op_address = (memory_readb(cpu.PC) + cpu.X) & 0xFF;
op_value = CPU_RAM[op_address];
cpu.PC++;
}
void cpu_address_zero_page_y() {
op_address = (memory_readb(cpu.PC) + cpu.Y) & 0xFF;
op_value = CPU_RAM[op_address];
cpu.PC++;
}
void cpu_address_absolute() {
op_address = memory_readw(cpu.PC);
op_value = memory_readb(op_address);
cpu.PC += 2;
}
void cpu_address_absolute_x() {
op_address = memory_readw(cpu.PC) + cpu.X;
op_value = memory_readb(op_address);
cpu.PC += 2;
if ((op_address >> 8) != (cpu.PC >> 8)) {
op_cycles++;
}
}
void cpu_address_absolute_y() {
op_address = (memory_readw(cpu.PC) + cpu.Y) & 0xFFFF;
op_value = memory_readb(op_address);
cpu.PC += 2;
if ((op_address >> 8) != (cpu.PC >> 8)) {
op_cycles++;
}
}
void cpu_address_relative() {
op_address = memory_readb(cpu.PC);
cpu.PC++;
if (op_address & 0x80)
op_address -= 0x100;
op_address += cpu.PC;
if ((op_address >> 8) != (cpu.PC >> 8)) {
op_cycles++;
}
}
void cpu_address_indirect() {
word arg_addr = memory_readw(cpu.PC);
// The famous 6502 bug when instead of reading from $C0FF/$C100 it reads from $C0FF/$C000
if ((arg_addr & 0xFF) == 0xFF) {
// Buggy code
op_address = (memory_readb(arg_addr & 0xFF00) << 8) + memory_readb(arg_addr);
}
else {
// Normal code
op_address = memory_readw(arg_addr);
}
cpu.PC += 2;
}
void cpu_address_indirect_x() {
byte arg_addr = memory_readb(cpu.PC);
op_address = (memory_readb((arg_addr + cpu.X + 1) & 0xFF) << 8) | memory_readb((arg_addr + cpu.X) & 0xFF);
op_value = memory_readb(op_address);
cpu.PC++;
}
void cpu_address_indirect_y() {
byte arg_addr = memory_readb(cpu.PC);
op_address = (((memory_readb((arg_addr + 1) & 0xFF) << 8) | memory_readb(arg_addr)) + cpu.Y) & 0xFFFF;
op_value = memory_readb(op_address);
cpu.PC++;
if ((op_address >> 8) != (cpu.PC >> 8)) {
op_cycles++;
}
}

View file

@ -0,0 +1,63 @@
#ifndef CPU_INTERNAL_H
#define CPU_INTERNAL_H
#include "common.h"
typedef enum {
carry_flag = 0x01,
zero_flag = 0x02,
interrupt_flag = 0x04,
decimal_flag = 0x08,
break_flag = 0x10,
unused_flag = 0x20,
overflow_flag = 0x40,
negative_flag = 0x80
} cpu_p_flag;
typedef enum {
carry_bp = 0,
zero_bp = 1,
interrupt_bp = 2,
decimal_bp = 3,
break_bp = 4,
unused_bp = 5,
overflow_bp = 6,
negative_bp = 7
} cpu_p_bp;
typedef struct {
word PC; // Program Counter,
byte SP; // Stack Pointer,
byte A, X, Y; // Registers
byte P; // Flag Register
} CPU_STATE;
extern CPU_STATE cpu;
extern byte CPU_RAM[0x8000];
extern int op_value, op_address; // Arguments for current instruction
extern int op_cycles; // Additional instruction cycles used (e.g. when paging occurs)
byte cpu_ram_read(word address);
void cpu_ram_write(word address, byte data);
// Interrupt Addresses
word cpu_nmi_interrupt_address();
word cpu_reset_interrupt_address();
word cpu_irq_interrupt_address();
// CPU Adressing Modes
void cpu_address_implied();
void cpu_address_immediate();
void cpu_address_zero_page();
void cpu_address_zero_page_x();
void cpu_address_zero_page_y();
void cpu_address_absolute();
void cpu_address_absolute_x();
void cpu_address_absolute_y();
void cpu_address_relative();
void cpu_address_indirect();
void cpu_address_indirect_x();
void cpu_address_indirect_y();
#endif

View file

@ -0,0 +1,606 @@
#include "cpu.h"
#include "cpu-internal.h"
#include "memory.h"
#include "ppu.h"
#include "common.h"
CPU_STATE cpu;
// CPU Memory
byte CPU_RAM[0x8000];
byte cpu_ram_read(word address) {
return CPU_RAM[address & 0x7FF];
}
void cpu_ram_write(word address, byte data) {
CPU_RAM[address & 0x7FF] = data;
}
static byte op_code; // Current instruction code
int op_value, op_address; // Arguments for current instruction
int op_cycles; // Additional instruction cycles used (e.g. when paging occurs)
static unsigned long long cpu_cycles; // Total CPU Cycles Since Power Up (wraps)
static void (*cpu_op_address_mode[256])(); // Array of address modes
static void (*cpu_op_handler[256])(); // Array of instruction function pointers
static bool cpu_op_in_base_instruction_set[256]; // true if instruction is in base 6502 instruction set
static char *cpu_op_name[256]; // Instruction names
static int cpu_op_cycles[256]; // CPU cycles used by instructions
static const byte cpu_zn_flag_table[256] = {
zero_flag,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,
};
// Interrupt Addresses
word cpu_nmi_interrupt_address() { return memory_readw(0xFFFA); }
word cpu_reset_interrupt_address() { return memory_readw(0xFFFC); }
word cpu_irq_interrupt_address() { return memory_readw(0xFFFE); }
// Stack Routines
void cpu_stack_pushb(byte data) { memory_writeb(0x100 + cpu.SP--, data); }
void cpu_stack_pushw(word data) { memory_writew(0xFF + cpu.SP, data); cpu.SP -= 2; }
byte cpu_stack_popb() { return memory_readb(0x100 + ++cpu.SP); }
word cpu_stack_popw() { cpu.SP += 2; return memory_readw(0xFF + cpu.SP); }
// CPU Instructions
void ____FE____() { /* Instruction for future Extension */ }
#define cpu_flag_set(flag) common_bit_set(cpu.P, flag)
#define cpu_modify_flag(flag, value) common_modify_bitb(&cpu.P, flag, value)
#define cpu_set_flag(flag) common_set_bitb(&cpu.P, flag)
#define cpu_unset_flag(flag) common_unset_bitb(&cpu.P, flag)
#define cpu_update_zn_flags(value) cpu.P = (cpu.P & ~(zero_flag | negative_flag)) | cpu_zn_flag_table[value]
#define cpu_branch(flag) if (flag) cpu.PC = op_address;
#define cpu_compare(reg) \
int result = reg - op_value; \
cpu_modify_flag(carry_bp, result >= 0); \
cpu_modify_flag(zero_bp, result == 0); \
cpu_modify_flag(negative_bp, (result >> 7) & 1);
// CPU Instructions
// NOP
void cpu_op_nop() {}
// Addition
void cpu_op_adc() {
int result = cpu.A + op_value + (cpu_flag_set(carry_bp) ? 1 : 0);
cpu_modify_flag(carry_bp, !!(result & 0x100));
cpu_modify_flag(overflow_bp, !!(~(cpu.A ^ op_value) & (cpu.A ^ result) & 0x80));
cpu.A = result & 0xFF;
cpu_update_zn_flags(cpu.A);
}
// Subtraction
void cpu_op_sbc() {
int result = cpu.A - op_value - (cpu_flag_set(carry_bp) ? 0 : 1);
cpu_modify_flag(carry_bp, !(result & 0x100));
cpu_modify_flag(overflow_bp, !!((cpu.A ^ op_value) & (cpu.A ^ result) & 0x80));
cpu.A = result & 0xFF;
cpu_update_zn_flags(cpu.A);
}
// Bit Manipulation Operations
void cpu_op_and() { cpu_update_zn_flags(cpu.A &= op_value); }
void cpu_op_bit() {
cpu_modify_flag(zero_bp, !(cpu.A & op_value));
cpu.P = (cpu.P & 0x3F) | (0xC0 & op_value);
}
void cpu_op_eor() { cpu_update_zn_flags(cpu.A ^= op_value); }
void cpu_op_ora() { cpu_update_zn_flags(cpu.A |= op_value); }
void cpu_op_asla() {
cpu_modify_flag(carry_bp, cpu.A & 0x80);
cpu.A <<= 1;
cpu_update_zn_flags(cpu.A);
}
void cpu_op_asl() {
cpu_modify_flag(carry_bp, op_value & 0x80);
op_value <<= 1;
op_value &= 0xFF;
cpu_update_zn_flags(op_value);
memory_writeb(op_address, op_value);
}
void cpu_op_lsra() {
int value = cpu.A >> 1;
cpu_modify_flag(carry_bp, cpu.A & 0x01);
cpu.A = value & 0xFF;
cpu_update_zn_flags(value);
}
void cpu_op_lsr() {
cpu_modify_flag(carry_bp, op_value & 0x01);
op_value >>= 1;
op_value &= 0xFF;
memory_writeb(op_address, op_value);
cpu_update_zn_flags(op_value);
}
void cpu_op_rola() {
int value = cpu.A << 1;
value |= cpu_flag_set(carry_bp) ? 1 : 0;
cpu_modify_flag(carry_bp, value > 0xFF);
cpu.A = value & 0xFF;
cpu_update_zn_flags(cpu.A);
}
void cpu_op_rol() {
op_value <<= 1;
op_value |= cpu_flag_set(carry_bp) ? 1 : 0;
cpu_modify_flag(carry_bp, op_value > 0xFF);
op_value &= 0xFF;
memory_writeb(op_address, op_value);
cpu_update_zn_flags(op_value);
}
void cpu_op_rora() {
unsigned char carry = cpu_flag_set(carry_bp);
cpu_modify_flag(carry_bp, cpu.A & 0x01);
cpu.A = (cpu.A >> 1) | (carry << 7);
cpu_modify_flag(zero_bp, cpu.A == 0);
cpu_modify_flag(negative_bp, !!carry);
}
void cpu_op_ror() {
unsigned char carry = cpu_flag_set(carry_bp);
cpu_modify_flag(carry_bp, op_value & 0x01);
op_value = ((op_value >> 1) | (carry << 7)) & 0xFF;
cpu_modify_flag(zero_bp, op_value == 0);
cpu_modify_flag(negative_bp, !!carry);
memory_writeb(op_address, op_value);
}
// Loading
void cpu_op_lda() { cpu_update_zn_flags(cpu.A = op_value); }
void cpu_op_ldx() { cpu_update_zn_flags(cpu.X = op_value); }
void cpu_op_ldy() { cpu_update_zn_flags(cpu.Y = op_value); }
// Storing
void cpu_op_sta() { memory_writeb(op_address, cpu.A); }
void cpu_op_stx() { memory_writeb(op_address, cpu.X); }
void cpu_op_sty() { memory_writeb(op_address, cpu.Y); }
// Transfering
void cpu_op_tax() { cpu_update_zn_flags(cpu.X = cpu.A); }
void cpu_op_txa() { cpu_update_zn_flags(cpu.A = cpu.X); }
void cpu_op_tay() { cpu_update_zn_flags(cpu.Y = cpu.A); }
void cpu_op_tya() { cpu_update_zn_flags(cpu.A = cpu.Y); }
void cpu_op_tsx() { cpu_update_zn_flags(cpu.X = cpu.SP); }
void cpu_op_txs() { cpu.SP = cpu.X; }
// Branching Positive
void cpu_op_bcs() { cpu_branch(cpu_flag_set(carry_bp)); }
void cpu_op_beq() { cpu_branch(cpu_flag_set(zero_bp)); }
void cpu_op_bmi() { cpu_branch(cpu_flag_set(negative_bp)); }
void cpu_op_bvs() { cpu_branch(cpu_flag_set(overflow_bp)); }
// Branching Negative
void cpu_op_bne() { cpu_branch(!cpu_flag_set(zero_bp)); }
void cpu_op_bcc() { cpu_branch(!cpu_flag_set(carry_bp)); }
void cpu_op_bpl() { cpu_branch(!cpu_flag_set(negative_bp)); }
void cpu_op_bvc() { cpu_branch(!cpu_flag_set(overflow_bp)); }
// Jumping
void cpu_op_jmp() { cpu.PC = op_address; }
// Subroutines
void cpu_op_jsr() { cpu_stack_pushw(cpu.PC - 1); cpu.PC = op_address; }
void cpu_op_rts() { cpu.PC = cpu_stack_popw() + 1; }
// Interruptions
void cpu_op_brk() {
cpu_stack_pushw(cpu.PC - 1);
cpu_stack_pushb(cpu.P);
cpu.P |= unused_flag | break_flag;
cpu.PC = cpu_nmi_interrupt_address();
}
void cpu_op_rti() { cpu.P = cpu_stack_popb() | unused_flag; cpu.PC = cpu_stack_popw(); }
// Flags
void cpu_op_clc() { cpu_unset_flag(carry_bp); }
void cpu_op_cld() { cpu_unset_flag(decimal_bp); }
void cpu_op_cli() { cpu_unset_flag(interrupt_bp); }
void cpu_op_clv() { cpu_unset_flag(overflow_bp); }
void cpu_op_sec() { cpu_set_flag(carry_bp); }
void cpu_op_sed() { cpu_set_flag(decimal_bp); }
void cpu_op_sei() { cpu_set_flag(interrupt_bp); }
// Comparison
void cpu_op_cmp() { cpu_compare(cpu.A); }
void cpu_op_cpx() { cpu_compare(cpu.X); }
void cpu_op_cpy() { cpu_compare(cpu.Y); }
// Increment
void cpu_op_inc() {
byte result = op_value + 1;
memory_writeb(op_address, result);
cpu_update_zn_flags(result);
}
void cpu_op_inx() { cpu_update_zn_flags(++cpu.X); }
void cpu_op_iny() { cpu_update_zn_flags(++cpu.Y); }
// Decrement
void cpu_op_dec() {
byte result = op_value - 1;
memory_writeb(op_address, result);
cpu_update_zn_flags(result);
}
void cpu_op_dex() { cpu_update_zn_flags(--cpu.X); }
void cpu_op_dey() { cpu_update_zn_flags(--cpu.Y); }
// Stack
void cpu_op_php() { cpu_stack_pushb(cpu.P | 0x30); }
void cpu_op_pha() { cpu_stack_pushb(cpu.A); }
void cpu_op_pla() { cpu.A = cpu_stack_popb(); cpu_update_zn_flags(cpu.A); }
void cpu_op_plp() { cpu.P = (cpu_stack_popb() & 0xEF) | 0x20; }
// Extended Instruction Set
void cpu_op_aso() { cpu_op_asl(); cpu_op_ora(); }
void cpu_op_axa() { memory_writeb(op_address, cpu.A & cpu.X & (op_address >> 8)); }
void cpu_op_axs() { memory_writeb(op_address, cpu.A & cpu.X); }
void cpu_op_dcm()
{
op_value--;
op_value &= 0xFF;
memory_writeb(op_address, op_value);
cpu_op_cmp();
}
void cpu_op_ins()
{
op_value = (op_value + 1) & 0xFF;
memory_writeb(op_address, op_value);
cpu_op_sbc();
}
void cpu_op_lax() { cpu_update_zn_flags(cpu.A = cpu.X = op_value); }
void cpu_op_lse() { cpu_op_lsr(); cpu_op_eor(); }
void cpu_op_rla() { cpu_op_rol(); cpu_op_and(); }
void cpu_op_rra() { cpu_op_ror(); cpu_op_adc(); }
// Base 6502 instruction set
#define CPU_OP_BIS(o, c, f, n, a) \
cpu_op_cycles[0x##o] = c; \
cpu_op_handler[0x##o] = cpu_op_##f; \
cpu_op_name[0x##o] = n; \
cpu_op_address_mode[0x##o] = cpu_address_##a; \
cpu_op_in_base_instruction_set[0x##o] = true;
// Not implemented instructions
#define CPU_OP_NII(o, a) \
cpu_op_cycles[0x##o] = 1; \
cpu_op_handler[0x##o] = ____FE____; \
cpu_op_name[0x##o] = "NOP"; \
cpu_op_address_mode[0x##o] = cpu_address_##a; \
cpu_op_in_base_instruction_set[0x##o] = false;
// Extended instruction set found in other CPUs and implemented for compatibility
#define CPU_OP_EIS(o, c, f, n, a) \
cpu_op_cycles[0x##o] = c; \
cpu_op_handler[0x##o] = cpu_op_##f; \
cpu_op_name[0x##o] = n; \
cpu_op_address_mode[0x##o] = cpu_address_##a; \
cpu_op_in_base_instruction_set[0x##o] = false;
// CPU Lifecycle
void cpu_init() {
CPU_OP_BIS(00, 7, brk, "BRK", implied)
CPU_OP_BIS(01, 6, ora, "ORA", indirect_x)
CPU_OP_BIS(05, 3, ora, "ORA", zero_page)
CPU_OP_BIS(06, 5, asl, "ASL", zero_page)
CPU_OP_BIS(08, 3, php, "PHP", implied)
CPU_OP_BIS(09, 2, ora, "ORA", immediate)
CPU_OP_BIS(0A, 2, asla,"ASL", implied)
CPU_OP_BIS(0D, 4, ora, "ORA", absolute)
CPU_OP_BIS(0E, 6, asl, "ASL", absolute)
CPU_OP_BIS(10, 2, bpl, "BPL", relative)
CPU_OP_BIS(11, 5, ora, "ORA", indirect_y)
CPU_OP_BIS(15, 4, ora, "ORA", zero_page_x)
CPU_OP_BIS(16, 6, asl, "ASL", zero_page_x)
CPU_OP_BIS(18, 2, clc, "CLC", implied)
CPU_OP_BIS(19, 4, ora, "ORA", absolute_y)
CPU_OP_BIS(1D, 4, ora, "ORA", absolute_x)
CPU_OP_BIS(1E, 7, asl, "ASL", absolute_x)
CPU_OP_BIS(20, 6, jsr, "JSR", absolute)
CPU_OP_BIS(21, 6, and, "AND", indirect_x)
CPU_OP_BIS(24, 3, bit, "BIT", zero_page)
CPU_OP_BIS(25, 3, and, "AND", zero_page)
CPU_OP_BIS(26, 5, rol, "ROL", zero_page)
CPU_OP_BIS(28, 4, plp, "PLP", implied)
CPU_OP_BIS(29, 2, and, "AND", immediate)
CPU_OP_BIS(2A, 2, rola,"ROL", implied)
CPU_OP_BIS(2C, 4, bit, "BIT", absolute)
CPU_OP_BIS(2D, 2, and, "AND", absolute)
CPU_OP_BIS(2E, 6, rol, "ROL", absolute)
CPU_OP_BIS(30, 2, bmi, "BMI", relative)
CPU_OP_BIS(31, 5, and, "AND", indirect_y)
CPU_OP_BIS(35, 4, and, "AND", zero_page_x)
CPU_OP_BIS(36, 6, rol, "ROL", zero_page_x)
CPU_OP_BIS(38, 2, sec, "SEC", implied)
CPU_OP_BIS(39, 4, and, "AND", absolute_y)
CPU_OP_BIS(3D, 4, and, "AND", absolute_x)
CPU_OP_BIS(3E, 7, rol, "ROL", absolute_x)
CPU_OP_BIS(40, 6, rti, "RTI", implied)
CPU_OP_BIS(41, 6, eor, "EOR", indirect_x)
CPU_OP_BIS(45, 3, eor, "EOR", zero_page)
CPU_OP_BIS(46, 5, lsr, "LSR", zero_page)
CPU_OP_BIS(48, 3, pha, "PHA", implied)
CPU_OP_BIS(49, 2, eor, "EOR", immediate)
CPU_OP_BIS(4A, 2, lsra,"LSR", implied)
CPU_OP_BIS(4C, 3, jmp, "JMP", absolute)
CPU_OP_BIS(4D, 4, eor, "EOR", absolute)
CPU_OP_BIS(4E, 6, lsr, "LSR", absolute)
CPU_OP_BIS(50, 2, bvc, "BVC", relative)
CPU_OP_BIS(51, 5, eor, "EOR", indirect_y)
CPU_OP_BIS(55, 4, eor, "EOR", zero_page_x)
CPU_OP_BIS(56, 6, lsr, "LSR", zero_page_x)
CPU_OP_BIS(58, 2, cli, "CLI", implied)
CPU_OP_BIS(59, 4, eor, "EOR", absolute_y)
CPU_OP_BIS(5D, 4, eor, "EOR", absolute_x)
CPU_OP_BIS(5E, 7, lsr, "LSR", absolute_x)
CPU_OP_BIS(60, 6, rts, "RTS", implied)
CPU_OP_BIS(61, 6, adc, "ADC", indirect_x)
CPU_OP_BIS(65, 3, adc, "ADC", zero_page)
CPU_OP_BIS(66, 5, ror, "ROR", zero_page)
CPU_OP_BIS(68, 4, pla, "PLA", implied)
CPU_OP_BIS(69, 2, adc, "ADC", immediate)
CPU_OP_BIS(6A, 2, rora,"ROR", implied)
CPU_OP_BIS(6C, 5, jmp, "JMP", indirect)
CPU_OP_BIS(6D, 4, adc, "ADC", absolute)
CPU_OP_BIS(6E, 6, ror, "ROR", absolute)
CPU_OP_BIS(70, 2, bvs, "BVS", relative)
CPU_OP_BIS(71, 5, adc, "ADC", indirect_y)
CPU_OP_BIS(75, 4, adc, "ADC", zero_page_x)
CPU_OP_BIS(76, 6, ror, "ROR", zero_page_x)
CPU_OP_BIS(78, 2, sei, "SEI", implied)
CPU_OP_BIS(79, 4, adc, "ADC", absolute_y)
CPU_OP_BIS(7D, 4, adc, "ADC", absolute_x)
CPU_OP_BIS(7E, 7, ror, "ROR", absolute_x)
CPU_OP_BIS(81, 6, sta, "STA", indirect_x)
CPU_OP_BIS(84, 3, sty, "STY", zero_page)
CPU_OP_BIS(85, 3, sta, "STA", zero_page)
CPU_OP_BIS(86, 3, stx, "STX", zero_page)
CPU_OP_BIS(88, 2, dey, "DEY", implied)
CPU_OP_BIS(8A, 2, txa, "TXA", implied)
CPU_OP_BIS(8C, 4, sty, "STY", absolute)
CPU_OP_BIS(8D, 4, sta, "STA", absolute)
CPU_OP_BIS(8E, 4, stx, "STX", absolute)
CPU_OP_BIS(90, 2, bcc, "BCC", relative)
CPU_OP_BIS(91, 6, sta, "STA", indirect_y)
CPU_OP_BIS(94, 4, sty, "STY", zero_page_x)
CPU_OP_BIS(95, 4, sta, "STA", zero_page_x)
CPU_OP_BIS(96, 4, stx, "STX", zero_page_y)
CPU_OP_BIS(98, 2, tya, "TYA", implied)
CPU_OP_BIS(99, 5, sta, "STA", absolute_y)
CPU_OP_BIS(9A, 2, txs, "TXS", implied)
CPU_OP_BIS(9D, 5, sta, "STA", absolute_x)
CPU_OP_BIS(A0, 2, ldy, "LDY", immediate)
CPU_OP_BIS(A1, 6, lda, "LDA", indirect_x)
CPU_OP_BIS(A2, 2, ldx, "LDX", immediate)
CPU_OP_BIS(A4, 3, ldy, "LDY", zero_page)
CPU_OP_BIS(A5, 3, lda, "LDA", zero_page)
CPU_OP_BIS(A6, 3, ldx, "LDX", zero_page)
CPU_OP_BIS(A8, 2, tay, "TAY", implied)
CPU_OP_BIS(A9, 2, lda, "LDA", immediate)
CPU_OP_BIS(AA, 2, tax, "TAX", implied)
CPU_OP_BIS(AC, 4, ldy, "LDY", absolute)
CPU_OP_BIS(AD, 4, lda, "LDA", absolute)
CPU_OP_BIS(AE, 4, ldx, "LDX", absolute)
CPU_OP_BIS(B0, 2, bcs, "BCS", relative)
CPU_OP_BIS(B1, 5, lda, "LDA", indirect_y)
CPU_OP_BIS(B4, 4, ldy, "LDY", zero_page_x)
CPU_OP_BIS(B5, 4, lda, "LDA", zero_page_x)
CPU_OP_BIS(B6, 4, ldx, "LDX", zero_page_y)
CPU_OP_BIS(B8, 2, clv, "CLV", implied)
CPU_OP_BIS(B9, 4, lda, "LDA", absolute_y)
CPU_OP_BIS(BA, 2, tsx, "TSX", implied)
CPU_OP_BIS(BC, 4, ldy, "LDY", absolute_x)
CPU_OP_BIS(BD, 4, lda, "LDA", absolute_x)
CPU_OP_BIS(BE, 4, ldx, "LDX", absolute_y)
CPU_OP_BIS(C0, 2, cpy, "CPY", immediate)
CPU_OP_BIS(C1, 6, cmp, "CMP", indirect_x)
CPU_OP_BIS(C4, 3, cpy, "CPY", zero_page)
CPU_OP_BIS(C5, 3, cmp, "CMP", zero_page)
CPU_OP_BIS(C6, 5, dec, "DEC", zero_page)
CPU_OP_BIS(C8, 2, iny, "INY", implied)
CPU_OP_BIS(C9, 2, cmp, "CMP", immediate)
CPU_OP_BIS(CA, 2, dex, "DEX", implied)
CPU_OP_BIS(CC, 4, cpy, "CPY", absolute)
CPU_OP_BIS(CD, 4, cmp, "CMP", absolute)
CPU_OP_BIS(CE, 6, dec, "DEC", absolute)
CPU_OP_BIS(D0, 2, bne, "BNE", relative)
CPU_OP_BIS(D1, 5, cmp, "CMP", indirect_y)
CPU_OP_BIS(D5, 4, cmp, "CMP", zero_page_x)
CPU_OP_BIS(D6, 6, dec, "DEC", zero_page_x)
CPU_OP_BIS(D8, 2, cld, "CLD", implied)
CPU_OP_BIS(D9, 4, cmp, "CMP", absolute_y)
CPU_OP_BIS(DD, 4, cmp, "CMP", absolute_x)
CPU_OP_BIS(DE, 7, dec, "DEC", absolute_x)
CPU_OP_BIS(E0, 2, cpx, "CPX", immediate)
CPU_OP_BIS(E1, 6, sbc, "SBC", indirect_x)
CPU_OP_BIS(E4, 3, cpx, "CPX", zero_page)
CPU_OP_BIS(E5, 3, sbc, "SBC", zero_page)
CPU_OP_BIS(E6, 5, inc, "INC", zero_page)
CPU_OP_BIS(E8, 2, inx, "INX", implied)
CPU_OP_BIS(E9, 2, sbc, "SBC", immediate)
CPU_OP_BIS(EA, 2, nop, "NOP", implied)
CPU_OP_BIS(EC, 4, cpx, "CPX", absolute)
CPU_OP_BIS(ED, 4, sbc, "SBC", absolute)
CPU_OP_BIS(EE, 6, inc, "INC", absolute)
CPU_OP_BIS(F0, 2, beq, "BEQ", relative)
CPU_OP_BIS(F1, 5, sbc, "SBC", indirect_y)
CPU_OP_BIS(F5, 4, sbc, "SBC", zero_page_x)
CPU_OP_BIS(F6, 6, inc, "INC", zero_page_x)
CPU_OP_BIS(F8, 2, sed, "SED", implied)
CPU_OP_BIS(F9, 4, sbc, "SBC", absolute_y)
CPU_OP_BIS(FD, 4, sbc, "SBC", absolute_x)
CPU_OP_BIS(FE, 7, inc, "INC", absolute_x)
CPU_OP_EIS(03, 8, aso, "SLO", indirect_x)
CPU_OP_EIS(07, 5, aso, "SLO", zero_page)
CPU_OP_EIS(0F, 6, aso, "SLO", absolute)
CPU_OP_EIS(13, 8, aso, "SLO", indirect_y)
CPU_OP_EIS(17, 6, aso, "SLO", zero_page_x)
CPU_OP_EIS(1B, 7, aso, "SLO", absolute_y)
CPU_OP_EIS(1F, 7, aso, "SLO", absolute_x)
CPU_OP_EIS(23, 8, rla, "RLA", indirect_x)
CPU_OP_EIS(27, 5, rla, "RLA", zero_page)
CPU_OP_EIS(2F, 6, rla, "RLA", absolute)
CPU_OP_EIS(33, 8, rla, "RLA", indirect_y)
CPU_OP_EIS(37, 6, rla, "RLA", zero_page_x)
CPU_OP_EIS(3B, 7, rla, "RLA", absolute_y)
CPU_OP_EIS(3F, 7, rla, "RLA", absolute_x)
CPU_OP_EIS(43, 8, lse, "SRE", indirect_x)
CPU_OP_EIS(47, 5, lse, "SRE", zero_page)
CPU_OP_EIS(4F, 6, lse, "SRE", absolute)
CPU_OP_EIS(53, 8, lse, "SRE", indirect_y)
CPU_OP_EIS(57, 6, lse, "SRE", zero_page_x)
CPU_OP_EIS(5B, 7, lse, "SRE", absolute_y)
CPU_OP_EIS(5F, 7, lse, "SRE", absolute_x)
CPU_OP_EIS(63, 8, rra, "RRA", indirect_x)
CPU_OP_EIS(67, 5, rra, "RRA", zero_page)
CPU_OP_EIS(6F, 6, rra, "RRA", absolute)
CPU_OP_EIS(73, 8, rra, "RRA", indirect_y)
CPU_OP_EIS(77, 6, rra, "RRA", zero_page_x)
CPU_OP_EIS(7B, 7, rra, "RRA", absolute_y)
CPU_OP_EIS(7F, 7, rra, "RRA", absolute_x)
CPU_OP_EIS(83, 6, axs, "SAX", indirect_x)
CPU_OP_EIS(87, 3, axs, "SAX", zero_page)
CPU_OP_EIS(8F, 4, axs, "SAX", absolute)
CPU_OP_EIS(93, 6, axa, "SAX", indirect_y)
CPU_OP_EIS(97, 4, axs, "SAX", zero_page_y)
CPU_OP_EIS(9F, 5, axa, "SAX", absolute_y)
CPU_OP_EIS(A3, 6, lax, "LAX", indirect_x)
CPU_OP_EIS(A7, 3, lax, "LAX", zero_page)
CPU_OP_EIS(AF, 4, lax, "LAX", absolute)
CPU_OP_EIS(B3, 5, lax, "LAX", indirect_y)
CPU_OP_EIS(B7, 4, lax, "LAX", zero_page_y)
CPU_OP_EIS(BF, 4, lax, "LAX", absolute_y)
CPU_OP_EIS(C3, 8, dcm, "DCP", indirect_x)
CPU_OP_EIS(C7, 5, dcm, "DCP", zero_page)
CPU_OP_EIS(CF, 6, dcm, "DCP", absolute)
CPU_OP_EIS(D3, 8, dcm, "DCP", indirect_y)
CPU_OP_EIS(D7, 6, dcm, "DCP", zero_page_x)
CPU_OP_EIS(DB, 7, dcm, "DCP", absolute_y)
CPU_OP_EIS(DF, 7, dcm, "DCP", absolute_x)
CPU_OP_EIS(E3, 8, ins, "ISB", indirect_x)
CPU_OP_EIS(E7, 5, ins, "ISB", zero_page)
CPU_OP_EIS(EB, 2, sbc, "SBC", immediate)
CPU_OP_EIS(EF, 6, ins, "ISB", absolute)
CPU_OP_EIS(F3, 8, ins, "ISB", indirect_y)
CPU_OP_EIS(F7, 6, ins, "ISB", zero_page_x)
CPU_OP_EIS(FB, 7, ins, "ISB", absolute_y)
CPU_OP_EIS(FF, 7, ins, "ISB", absolute_x)
CPU_OP_NII(04, zero_page)
CPU_OP_NII(0C, absolute)
CPU_OP_NII(14, zero_page_x)
CPU_OP_NII(1A, implied)
CPU_OP_NII(1C, absolute_x)
CPU_OP_NII(34, zero_page_x)
CPU_OP_NII(3A, implied)
CPU_OP_NII(3C, absolute_x)
CPU_OP_NII(44, zero_page)
CPU_OP_NII(54, zero_page_x)
CPU_OP_NII(5A, implied)
CPU_OP_NII(5C, absolute_x)
CPU_OP_NII(64, zero_page)
CPU_OP_NII(74, zero_page_x)
CPU_OP_NII(7A, implied)
CPU_OP_NII(7C, absolute_x)
CPU_OP_NII(80, immediate)
CPU_OP_NII(D4, zero_page_x)
CPU_OP_NII(DA, implied)
CPU_OP_NII(DC, absolute_x)
CPU_OP_NII(F4, zero_page_x)
CPU_OP_NII(FA, implied)
CPU_OP_NII(FC, absolute_x)
cpu.P = 0x24;
cpu.SP = 0x00;
cpu.A = cpu.X = cpu.Y = 0;
}
void cpu_reset() {
cpu.PC = cpu_reset_interrupt_address();
cpu.SP -= 3;
cpu.P |= interrupt_flag;
}
void cpu_interrupt() {
if (ppu_generates_nmi()) {
cpu.P |= interrupt_flag;
cpu_unset_flag(unused_bp);
cpu_stack_pushw(cpu.PC);
cpu_stack_pushb(cpu.P);
cpu.PC = cpu_nmi_interrupt_address();
}
}
unsigned long long cpu_clock() {
return cpu_cycles;
}
void cpu_run(long cycles) {
cycles /= 3;
while (cycles > 0) {
op_code = memory_readb(cpu.PC++);
if (cpu_op_address_mode[op_code] == NULL) {
}
else {
cpu_op_address_mode[op_code]();
cpu_op_handler[op_code]();
}
cycles -= cpu_op_cycles[op_code] + op_cycles;
cpu_cycles -= cpu_op_cycles[op_code] + op_cycles;
op_cycles = 0;
}
}

View file

@ -0,0 +1,17 @@
#include "common.h"
#ifndef CPU_H
#define CPU_H
byte cpu_ram_read(word address);
void cpu_ram_write(word address, byte data);
void cpu_init();
void cpu_reset();
void cpu_interrupt();
void cpu_run(long cycles);
// CPU cycles that passed since power up
unsigned long long cpu_clock();
#endif

View file

@ -0,0 +1,140 @@
#include "fce.h"
#include "cpu.h"
#include "memory.h"
#include "ppu.h"
#include "psg.h"
#include <klib.h>
static int frame_cnt;
static inline bool candraw() { return frame_cnt % (1 + FRAME_SKIP) == 0; }
static uint32_t canvas[SCR_W * SCR_H];
void draw(int x, int y, int idx) {
if (x >= 0 && x < SCR_W && y >= 0 && y < SCR_H && candraw()) {
canvas[y * SCR_W + x] = palette[idx];
}
}
typedef struct {
char signature[4];
byte prg_block_count;
byte chr_block_count;
word rom_type;
byte reserved[8];
} ines_header;
static byte *buf;
static ines_header *fce_rom_header;
byte *romread(int size) {
byte *ret = buf;
buf += size;
return ret;
}
int fce_load_rom(char *rom) {
buf = (byte*)rom;
fce_rom_header = (ines_header*)romread(sizeof(ines_header));
if (memcmp(fce_rom_header->signature, "NES\x1A", 4)) {
return -1;
}
mmc_id = ((fce_rom_header->rom_type & 0xF0) >> 4);
int prg_size = fce_rom_header->prg_block_count * 0x4000;
byte *blk = romread(prg_size);
if (mmc_id == 0 || mmc_id == 3) {
// if there is only one PRG block, we must repeat it twice
if (fce_rom_header->prg_block_count == 1) {
mmc_copy(0x8000, blk, 0x4000);
mmc_copy(0xC000, blk, 0x4000);
}
else {
mmc_copy(0x8000, blk, 0x8000);
}
}
else {
return -1;
}
// Copying CHR pages into MMC and PPU
int i;
for (i = 0; i < fce_rom_header->chr_block_count; i++) {
byte *blk = romread(0x2000);
mmc_append_chr_rom_page(blk);
if (i == 0) {
ppu_copy(0x0000, blk, 0x2000);
}
}
return 0;
}
void fce_init() {
cpu_init();
ppu_init();
ppu_set_mirroring(fce_rom_header->rom_type & 1);
cpu_reset();
}
static int gtime;
static inline int uptime_ms() {
return io_read(AM_TIMER_UPTIME).us / 1000;
}
void wait_for_frame() {
int cur = uptime_ms();
while (cur - gtime < 1000 / FPS) {
cur = uptime_ms();
}
gtime = cur;
}
// FCE Lifecycle
void fce_run() {
gtime = uptime_ms();
int nr_draw = 0;
uint32_t last = gtime;
while(1) {
wait_for_frame();
int scanlines = 262;
while (scanlines-- > 0) {
ppu_cycle();
psg_detect_key();
}
nr_draw ++;
int upt = uptime_ms();
if (upt - last > 1000) {
last = upt;
for (int i = 0; i < 80; i++) putch('\b');
printf("(System time: %ds) FPS = %d", upt / 1000, nr_draw);
nr_draw = 0;
}
}
}
void fce_update_screen() {
frame_cnt++;
if (!candraw()) return;
int idx = ppu_ram_read(0x3F00);
uint32_t bgc = palette[idx];
AM_GPU_CONFIG_T cfg = io_read(AM_GPU_CONFIG);
int xpad = (cfg.width - SCR_W) / 2;
int ypad = (cfg.height - SCR_H) / 2;
panic_on(xpad < 0 || ypad < 0, "screen too small");
io_write(AM_GPU_FBDRAW, xpad, ypad, canvas, SCR_W, SCR_H, true);
for (int i = 0; i < SCR_W * SCR_H; i ++) canvas[i] = bgc;
}

View file

@ -0,0 +1,28 @@
#ifndef FCE_H
#define FCE_H
#include "common.h"
#define FPS 60
#define SCR_W 256
#define SCR_H 240
#define FRAME_SKIP 1
void fce_update_screen();
int fce_load_rom(char *rom);
void fce_init();
void fce_run();
void draw(int x, int y, int idx);
static const uint32_t palette[64] = {
0x808080, 0x0000BB, 0x3700BF, 0x8400A6, 0xBB006A, 0xB7001E, 0xB30000, 0x912600,
0x7B2B00, 0x003E00, 0x00480D, 0x003C22, 0x002F66, 0x000000, 0x050505, 0x050505,
0xC8C8C8, 0x0059FF, 0x443CFF, 0xB733CC, 0xFF33AA, 0xFF375E, 0xFF371A, 0xD54B00,
0xC46200, 0x3C7B00, 0x1E8415, 0x009566, 0x0084C4, 0x111111, 0x090909, 0x090909,
0xFFFFFF, 0x0095FF, 0x6F84FF, 0xD56FFF, 0xFF77CC, 0xFF6F99, 0xFF7B59, 0xFF915F,
0xFFA233, 0xA6BF00, 0x51D96A, 0x4DD5AE, 0x00D9FF, 0x666666, 0x0D0D0D, 0x0D0D0D,
0xFFFFFF, 0x84BFFF, 0xBBBBFF, 0xD0BBFF, 0xFFBFEA, 0xFFBFCC, 0xFFC4B7, 0xFFCCAE,
0xFFD9A2, 0xCCE199, 0xAEEEB7, 0xAAF7EE, 0xB3EEFF, 0xDDDDDD, 0x111111, 0x111111
};
#endif

View file

@ -0,0 +1,22 @@
#include "common.h"
#include "fce.h"
#include "psg.h"
extern char rom_mario_nes[];
int main() {
ioe_init();
printf("==================== LiteNES Emulator ====================\n\n");
printf("Control: [%s] SELECT [%s] START [%s]\n"
" [%s] [%s] [%s] A [%s] B [%s]\n\n",
TOSTRING(KEY_UP), TOSTRING(KEY_SELECT), TOSTRING(KEY_START),
TOSTRING(KEY_LEFT), TOSTRING(KEY_DOWN), TOSTRING(KEY_RIGHT),
TOSTRING(KEY_A), TOSTRING(KEY_B));
printf("==========================================================\n");
fce_load_rom((void *)rom_mario_nes);
fce_init();
fce_run();
return 1;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,41 @@
#include "memory.h"
#include "cpu.h"
#include "ppu.h"
#include "psg.h"
byte memory_readb(word address) {
switch (address >> 13) {
case 0: return cpu_ram_read(address & 0x07FF);
case 1: return ppuio_read(address);
case 2: return psgio_read(address);
case 3: return cpu_ram_read(address & 0x1FFF);
default: return mmc_read(address);
}
}
void memory_writeb(word address, byte data) {
// DMA transfer
int i;
if (address == 0x4014) {
for (i = 0; i < 256; i++) {
ppu_sprram_write(cpu_ram_read((0x100 * data) + i));
}
return;
}
switch (address >> 13) {
case 0: return cpu_ram_write(address & 0x07FF, data);
case 1: return ppuio_write(address, data);
case 2: return psgio_write(address, data);
case 3: return cpu_ram_write(address & 0x1FFF, data);
default: return mmc_write(address, data);
}
}
word memory_readw(word address) {
return memory_readb(address) + (memory_readb(address + 1) << 8);
}
void memory_writew(word address, word data) {
memory_writeb(address, data & 0xFF);
memory_writeb(address + 1, data >> 8);
}

View file

@ -0,0 +1,15 @@
#ifndef MEM_H
#define MEM_H
#include "common.h"
#include "mmc.h"
// Single byte
byte memory_readb(word address);
void memory_writeb(word address, byte data);
// Two bytes (word), LSB first
word memory_readw(word address);
void memory_writew(word address, word data);
#endif

View file

@ -0,0 +1,31 @@
#include "mmc.h"
#include "ppu.h"
#include <klib.h>
byte mmc_id;
#define MMC_MAX_PAGE_COUNT 1
static byte mmc_chr_pages[MMC_MAX_PAGE_COUNT][0x2000];
static int mmc_chr_pages_number;
byte memory[0x10000];
byte mmc_read(word address) {
return memory[address];
}
void mmc_write(word address, byte data) {
switch (mmc_id) {
case 0x3: ppu_copy(0x0000, &mmc_chr_pages[data & 3][0], 0x2000); break;
}
memory[address] = data;
}
void mmc_copy(word address, byte *source, int length) {
memcpy(&memory[address], source, length);
}
void mmc_append_chr_rom_page(byte *source) {
assert(mmc_chr_pages_number < MMC_MAX_PAGE_COUNT);
memcpy(&mmc_chr_pages[mmc_chr_pages_number++][0], source, 0x2000);
}

View file

@ -0,0 +1,8 @@
#include "common.h"
extern byte mmc_id;
byte mmc_read(word address);
void mmc_write(word address, byte data);
void mmc_copy(word address, byte *source, int length);
void mmc_append_chr_rom_page(byte *source);

View file

@ -0,0 +1,432 @@
#include "ppu.h"
#include "cpu.h"
#include "fce.h"
#include "memory.h"
#include <klib.h>
//#define PROFILE
//#define HAS_US_TIMER
PPU_STATE ppu;
static bool ppu_2007_first_read;
static byte ppu_addr_latch;
static byte PPU_SPRRAM[0x100];
static byte PPU_RAM[0x4000];
static bool ppu_sprite_hit_occured = false;
static byte ppu_latch;
// PPU Constants
static const word ppu_base_nametable_addresses[4] = { 0x2000, 0x2400, 0x2800, 0x2C00 };
// For sprite-0-hit checks
static byte ppu_screen_background[264][248];
// Precalculated tile high and low bytes addition for pattern tables
static byte ppu_l_h_addition_table[256][256][8];
static byte ppu_l_h_addition_flip_table[256][256][8];
// PPUCTRL Functions
word ppu_base_nametable_address() { return ppu_base_nametable_addresses[ppu.PPUCTRL & 0x3]; }
byte ppu_vram_address_increment() { return common_bit_set(ppu.PPUCTRL, 2) ? 32 : 1; }
word ppu_sprite_pattern_table_address() { return common_bit_set(ppu.PPUCTRL, 3) ? 0x1000 : 0x0000; }
word ppu_background_pattern_table_address() { return common_bit_set(ppu.PPUCTRL, 4) ? 0x1000 : 0x0000; }
byte ppu_sprite_height() { return common_bit_set(ppu.PPUCTRL, 5) ? 16 : 8; }
bool ppu_generates_nmi() { return common_bit_set(ppu.PPUCTRL, 7); }
// PPUMASK Functions
bool ppu_renders_grayscale() { return common_bit_set(ppu.PPUMASK, 0); }
bool ppu_shows_background_in_leftmost_8px() { return common_bit_set(ppu.PPUMASK, 1); }
bool ppu_shows_sprites_in_leftmost_8px() { return common_bit_set(ppu.PPUMASK, 2); }
bool ppu_shows_background() { return common_bit_set(ppu.PPUMASK, 3); }
bool ppu_shows_sprites() { return common_bit_set(ppu.PPUMASK, 4); }
bool ppu_intensifies_reds() { return common_bit_set(ppu.PPUMASK, 5); }
bool ppu_intensifies_greens() { return common_bit_set(ppu.PPUMASK, 6); }
bool ppu_intensifies_blues() { return common_bit_set(ppu.PPUMASK, 7); }
void ppu_set_renders_grayscale(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 0, yesno); }
void ppu_set_shows_background_in_leftmost_8px(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 1, yesno); }
void ppu_set_shows_sprites_in_leftmost_8px(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 2, yesno); }
void ppu_set_shows_background(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 3, yesno); }
void ppu_set_shows_sprites(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 4, yesno); }
void ppu_set_intensifies_reds(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 5, yesno); }
void ppu_set_intensifies_greens(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 6, yesno); }
void ppu_set_intensifies_blues(bool yesno) { common_modify_bitb(&ppu.PPUMASK, 7, yesno); }
// PPUSTATUS Functions
bool ppu_sprite_overflow() { return common_bit_set(ppu.PPUSTATUS, 5); }
bool ppu_sprite_0_hit() { return common_bit_set(ppu.PPUSTATUS, 6); }
bool ppu_in_vblank() { return common_bit_set(ppu.PPUSTATUS, 7); }
void ppu_set_sprite_overflow(bool yesno) { common_modify_bitb(&ppu.PPUSTATUS, 5, yesno); }
void ppu_set_sprite_0_hit(bool yesno) { common_modify_bitb(&ppu.PPUSTATUS, 6, yesno); }
void ppu_set_in_vblank(bool yesno) { common_modify_bitb(&ppu.PPUSTATUS, 7, yesno); }
// RAM
word ppu_get_real_ram_address(word address) {
if (address < 0x2000) { return address; }
else if (address < 0x3F00) {
if (address < 0x3000) { return address; }
else { return address; }
}
else if (address < 0x4000) {
address = 0x3F00 | (address & 0x1F);
if (address == 0x3F10 || address == 0x3F14 || address == 0x3F18 || address == 0x3F1C)
address -= 0x10;
return address;
}
return 0xFFFF;
}
byte ppu_ram_read(word address) {
return PPU_RAM[ppu_get_real_ram_address(address)];
}
void ppu_ram_write(word address, byte data) {
PPU_RAM[ppu_get_real_ram_address(address)] = data;
}
// 3F01 = 0F (00001111)
// 3F02 = 2A (00101010)
// 3F03 = 09 (00001001)
// 3F04 = 07 (00000111)
// 3F05 = 0F (00001111)
// 3F06 = 30 (00110000)
// 3F07 = 27 (00100111)
// 3F08 = 15 (00010101)
// 3F09 = 0F (00001111)
// 3F0A = 30 (00110000)
// 3F0B = 02 (00000010)
// 3F0C = 21 (00100001)
// 3F0D = 0F (00001111)
// 3F0E = 30 (00110000)
// 3F0F = 00 (00000000)
// 3F11 = 0F (00001111)
// 3F12 = 16 (00010110)
// 3F13 = 12 (00010010)
// 3F14 = 37 (00110111)
// 3F15 = 0F (00001111)
// 3F16 = 12 (00010010)
// 3F17 = 16 (00010110)
// 3F18 = 37 (00110111)
// 3F19 = 0F (00001111)
// 3F1A = 17 (00010111)
// 3F1B = 11 (00010001)
// 3F1C = 35 (00110101)
// 3F1D = 0F (00001111)
// 3F1E = 17 (00010111)
// 3F1F = 11 (00010001)
// 3F20 = 2B (00101011)
// Rendering
void ppu_draw_background_scanline(bool mirror) {
int tile_x;
for (tile_x = ppu_shows_background_in_leftmost_8px() ? 0 : 1; tile_x < 32; tile_x ++) {
// Skipping off-screen pixels
if (((tile_x << 3) - ppu.PPUSCROLL_X + (mirror ? 256 : 0)) > 256)
continue;
int tile_y = ppu.scanline >> 3;
int tile_index = ppu_ram_read(ppu_base_nametable_address() + tile_x + (tile_y << 5) + (mirror ? 0x400 : 0));
word tile_address = ppu_background_pattern_table_address() + 16 * tile_index;
int y_in_tile = ppu.scanline & 0x7;
byte l = ppu_ram_read(tile_address + y_in_tile);
byte h = ppu_ram_read(tile_address + y_in_tile + 8);
int x;
for (x = 0; x < 8; x ++) {
byte color = ppu_l_h_addition_table[l][h][x];
// Color 0 is transparent
if (color != 0) {
word attribute_address = (ppu_base_nametable_address() + (mirror ? 0x400 : 0) + 0x3C0 + (tile_x >> 2) + (ppu.scanline >> 5) * 8);
bool top = (ppu.scanline % 32) < 16;
bool left = (tile_x % 4 < 2);
byte palette_attribute = ppu_ram_read(attribute_address);
if (!top) { palette_attribute >>= 4; }
if (!left) { palette_attribute >>= 2; }
palette_attribute &= 3;
word palette_address = 0x3F00 + (palette_attribute << 2);
int idx = ppu_ram_read(palette_address + color);
ppu_screen_background[(tile_x << 3) + x][ppu.scanline] = color;
draw((tile_x << 3) + x - ppu.PPUSCROLL_X + (mirror ? 256 : 0), ppu.scanline + 1, idx); // bg
}
}
}
}
void ppu_draw_sprite_scanline() {
int scanline_sprite_count = 0;
int n;
for (n = 0; n < 0x100; n += 4) {
byte sprite_x = PPU_SPRRAM[n + 3];
byte sprite_y = PPU_SPRRAM[n];
// Skip if sprite not on scanline
if (sprite_y > ppu.scanline || sprite_y + ppu_sprite_height() < ppu.scanline)
continue;
scanline_sprite_count++;
// PPU can't render > 8 sprites
if (scanline_sprite_count > 8) {
ppu_set_sprite_overflow(true);
// break;
}
bool vflip = PPU_SPRRAM[n + 2] & 0x80;
bool hflip = PPU_SPRRAM[n + 2] & 0x40;
word tile_address = ppu_sprite_pattern_table_address() + 16 * PPU_SPRRAM[n + 1];
int y_in_tile = ppu.scanline & 0x7;
byte l = ppu_ram_read(tile_address + (vflip ? (7 - y_in_tile) : y_in_tile));
byte h = ppu_ram_read(tile_address + (vflip ? (7 - y_in_tile) : y_in_tile) + 8);
byte palette_attribute = PPU_SPRRAM[n + 2] & 0x3;
word palette_address = 0x3F10 + (palette_attribute << 2);
int x;
for (x = 0; x < 8; x ++) {
int color = hflip ? ppu_l_h_addition_flip_table[l][h][x] : ppu_l_h_addition_table[l][h][x];
// Color 0 is transparent
if (color != 0) {
int screen_x = sprite_x + x;
int idx = ppu_ram_read(palette_address + color);
// FIXME: we do not distinguish bbg and fg here to improve performance
if (PPU_SPRRAM[n + 2] & 0x20) {
draw(screen_x, sprite_y + y_in_tile + 1, idx); // bbg
}
else {
draw(screen_x, sprite_y + y_in_tile + 1, idx); // fg
}
// Checking sprite 0 hit
if (ppu_shows_background() && !ppu_sprite_hit_occured && n == 0 && ppu_screen_background[screen_x][sprite_y + y_in_tile] == color) {
ppu_set_sprite_0_hit(true);
ppu_sprite_hit_occured = true;
}
}
}
}
}
// PPU Lifecycle
void ppu_run(int cycles) {
while (cycles-- > 0) { ppu_cycle(); }
}
static uint32_t background_time, sprite_time, cpu_time;
#ifdef PROFILE
#ifdef HAS_US_TIMER
# define TIMER_UNIT "us"
# define time_read(x) read_us(&x)
# define time_diff(t1, t0) us_timediff(&t1, &t0)
# define TIME_TYPE amtime
#else
# define TIMER_UNIT "ms"
# define time_read(x) x = uptime()
# define time_diff(t1, t0) (t1 - t0)
# define TIME_TYPE uint32_t
#endif
#else
# define time_read(x)
# define time_diff(t1, t0) 0
#endif
void ppu_cycle() {
#ifdef PROFILE
TIME_TYPE t0, t1, t2, t3, t4, t5;
#endif
if (!ppu.ready && cpu_clock() > 29658)
ppu.ready = true;
time_read(t0);
cpu_run(256);
time_read(t1);
ppu.scanline++;
if (ppu.scanline < SCR_H && ppu_shows_background()) {
ppu_draw_background_scanline(false);
ppu_draw_background_scanline(true);
}
time_read(t2);
cpu_run(85 - 16);
time_read(t3);
if (ppu.scanline < SCR_H && ppu_shows_sprites()) {
ppu_draw_sprite_scanline();
}
time_read(t4);
cpu_run(16);
time_read(t5);
cpu_time += time_diff(t1, t0) + time_diff(t3, t2) + time_diff(t5, t4);
background_time += time_diff(t2, t1);
sprite_time += time_diff(t4, t3);
if (ppu.scanline == 241) {
ppu_set_in_vblank(true);
ppu_set_sprite_0_hit(false);
cpu_interrupt();
}
else if (ppu.scanline == 262) {
ppu.scanline = -1;
ppu_sprite_hit_occured = false;
ppu_set_in_vblank(false);
time_read(t0);
fce_update_screen();
time_read(t1);
#ifdef PROFILE
uint32_t total = cpu_time + background_time + sprite_time + time_diff(t1, t0);
printf("Time: cpu + bg + spr + scr = (%d + %d + %d + %d)\t= %d %s\n",
cpu_time, background_time, sprite_time, time_diff(t1, t0), total, TIMER_UNIT);
#endif
cpu_time = 0;
background_time = 0;
sprite_time = 0;
}
}
void ppu_copy(word address, byte *source, int length) {
memcpy(&PPU_RAM[address], source, length);
}
byte ppuio_read(word address) {
ppu.PPUADDR &= 0x3FFF;
switch (address & 7) {
case 2:
{
byte value = ppu.PPUSTATUS;
ppu_set_in_vblank(false);
ppu_set_sprite_0_hit(false);
ppu.scroll_received_x = 0;
ppu.PPUSCROLL = 0;
ppu.addr_received_high_byte = 0;
ppu_latch = value;
ppu_addr_latch = 0;
ppu_2007_first_read = true;
return value;
}
case 4: return ppu_latch = PPU_SPRRAM[ppu.OAMADDR];
case 7:
{
byte data;
if (ppu.PPUADDR < 0x3F00) {
data = ppu_latch = ppu_ram_read(ppu.PPUADDR);
}
else {
data = ppu_ram_read(ppu.PPUADDR);
ppu_latch = 0;
}
if (ppu_2007_first_read) {
ppu_2007_first_read = false;
}
else {
ppu.PPUADDR += ppu_vram_address_increment();
}
return data;
}
default: return 0xFF;
}
}
void ppuio_write(word address, byte data) {
address &= 7;
ppu_latch = data;
ppu.PPUADDR &= 0x3FFF;
switch(address) {
case 0: if (ppu.ready) ppu.PPUCTRL = data; break;
case 1: if (ppu.ready) ppu.PPUMASK = data; break;
case 3: ppu.OAMADDR = data; break;
case 4: PPU_SPRRAM[ppu.OAMADDR++] = data; break;
case 5:
{
if (ppu.scroll_received_x)
ppu.PPUSCROLL_Y = data;
else
ppu.PPUSCROLL_X = data;
ppu.scroll_received_x ^= 1;
break;
}
case 6:
{
if (!ppu.ready)
return;
if (ppu.addr_received_high_byte)
ppu.PPUADDR = (ppu_addr_latch << 8) + data;
else
ppu_addr_latch = data;
ppu.addr_received_high_byte ^= 1;
ppu_2007_first_read = true;
break;
}
case 7:
{
if (ppu.PPUADDR > 0x1FFF || ppu.PPUADDR < 0x4000) {
ppu_ram_write(ppu.PPUADDR ^ ppu.mirroring_xor, data);
ppu_ram_write(ppu.PPUADDR, data);
}
else {
ppu_ram_write(ppu.PPUADDR, data);
}
}
}
ppu_latch = data;
}
void ppu_init() {
ppu.PPUCTRL = ppu.PPUMASK = ppu.PPUSTATUS = ppu.OAMADDR = ppu.PPUSCROLL_X = ppu.PPUSCROLL_Y = ppu.PPUADDR = 0;
ppu.PPUSTATUS |= 0xA0;
ppu.PPUDATA = 0;
ppu_2007_first_read = true;
// Initializing low-high byte-pairs for pattern tables
int h, l, x;
for (h = 0; h < 0x100; h ++) {
for (l = 0; l < 0x100; l ++) {
for (x = 0; x < 8; x ++) {
ppu_l_h_addition_table[l][h][x] = (((h >> (7 - x)) & 1) << 1) | ((l >> (7 - x)) & 1);
ppu_l_h_addition_flip_table[l][h][x] = (((h >> x) & 1) << 1) | ((l >> x) & 1);
}
}
}
}
void ppu_sprram_write(byte data) {
PPU_SPRRAM[ppu.OAMADDR++] = data;
}
void ppu_set_background_color(byte color) {
}
void ppu_set_mirroring(byte mirroring) {
ppu.mirroring = mirroring;
ppu.mirroring_xor = 0x400 << mirroring;
}

View file

@ -0,0 +1,41 @@
#ifndef PPU_H
#define PPU_H
#include "common.h"
typedef struct {
byte PPUCTRL; // $2000 write only
byte PPUMASK; // $2001 write only
byte PPUSTATUS; // $2002 read only
byte OAMADDR; // $2003 write only
byte OAMDATA; // $2004
word PPUSCROLL;
byte PPUSCROLL_X, PPUSCROLL_Y; // $2005 write only x2
word PPUADDR; // $2006 write only x2
word PPUDATA; // $2007
bool scroll_received_x;
bool addr_received_high_byte;
bool ready;
int mirroring, mirroring_xor;
int x, scanline;
} PPU_STATE;
void ppu_init();
byte ppu_ram_read(word address);
void ppu_ram_write(word address, byte data);
byte ppuio_read(word address);
void ppuio_write(word address, byte data);
bool ppu_generates_nmi();
void ppu_set_mirroring(byte mirroring);
void ppu_cycle();
void ppu_copy(word address, byte *source, int length);
void ppu_sprram_write(byte data);
#endif

View file

@ -0,0 +1,54 @@
#include "psg.h"
#include <klib.h>
static int p = 10;
static int key_state[256];
#define KEYS \
CONCAT(AM_KEY_, KEY_A), \
CONCAT(AM_KEY_, KEY_B), \
CONCAT(AM_KEY_, KEY_SELECT), \
CONCAT(AM_KEY_, KEY_START), \
CONCAT(AM_KEY_, KEY_UP), \
CONCAT(AM_KEY_, KEY_DOWN), \
CONCAT(AM_KEY_, KEY_LEFT), \
CONCAT(AM_KEY_, KEY_RIGHT),
static int MAP[256] = {
0, // On/Off
KEYS
255,
};
byte psgio_read(word address) {
// Joystick 1
if (address == 0x4016) {
if (p++ < 9) {
return key_state[MAP[p]];
}
}
return 0;
}
void psgio_write(word address, byte data) {
static byte prev_write;
if (address == 0x4016) {
if ((data & 1) == 0 && prev_write == 1) {
// strobe
p = 0;
}
}
prev_write = data & 1;
}
void psg_detect_key() {
while (1) {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
if (ev.keycode == AM_KEY_NONE) break;
key_state[ev.keycode] = ev.keydown;
}
}
void psg_init() {
key_state[0] = 1;
}

View file

@ -0,0 +1,20 @@
#ifndef PSG_H
#define PSG_H
#include "common.h"
#define KEY_A J
#define KEY_B K
#define KEY_SELECT U
#define KEY_START I
#define KEY_UP W
#define KEY_DOWN S
#define KEY_LEFT A
#define KEY_RIGHT D
byte psgio_read(word address);
void psgio_write(word address, byte data);
void psg_init();
void psg_detect_key();
#endif

View file

@ -0,0 +1,31 @@
ARCH_SPLIT = $(subst -, ,$(ARCH))
ISA = $(word 1,$(ARCH_SPLIT))
PLATFORM = $(word 2,$(ARCH_SPLIT))
ifneq ($(PLATFORM), nemu)
$(error Only support with NEMU)
endif
TMPDEFCONFIG = tmp_defconfig
TMPDEFCONFIG_FILE = $(NEMU_HOME)/configs/$(TMPDEFCONFIG)
all:
$(MAKE) save_config
$(MAKE) build_am
$(MAKE) restore_config
$(MAKE) -C $(NEMU_HOME) run IMG=$(NEMU_HOME)/build/$(ISA)-nemu-interpreter-$(ARCH).bin
save_config:
$(MAKE) -C $(NEMU_HOME) savedefconfig
mv $(NEMU_HOME)/configs/defconfig $(TMPDEFCONFIG_FILE)
build_am:
$(MAKE) -C $(NEMU_HOME) $(ISA)-am_defconfig
$(MAKE) -C $(NEMU_HOME) ARCH=$(ARCH) mainargs=$(mainargs) || \
($(MAKE) restore_config; false)
restore_config:
$(MAKE) -C $(NEMU_HOME) ARCH=$(ARCH) $(TMPDEFCONFIG)
rm $(TMPDEFCONFIG_FILE)
.PHONY: all save_config build_am restore_config

View file

@ -0,0 +1,3 @@
NAME = slider
SRCS = main.c image.S
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,7 @@
.section .data
.global image, image_end
.p2align 3
image:
.incbin "images/projectn.bin"
.incbin "images/litenes.bin"
image_end:

View file

@ -0,0 +1 @@
!*.bin

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,32 @@
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
extern uint32_t image[][400][300];
extern uint32_t image_end[][400][300];
#define NR_IMG (image_end - image)
void display_image(int i) {
io_write(AM_GPU_FBDRAW, 0, 0, &image[i][0][0], 400, 300, true);
}
int main() {
ioe_init();
int i = 0;
unsigned long last = 0;
unsigned long current;
display_image(i);
while (1) {
current = io_read(AM_TIMER_UPTIME).us / 1000;
if (current - last > 5000) {
// change image every 5s
i = (i + 1) % NR_IMG;
display_image(i);
last = current;
}
}
return 0;
}

View file

@ -0,0 +1,42 @@
This software is licensed under a BSD Style License
Copyright (c) 2015 Battelle Memorial Institute. All Rights Reserved.
http://www.battelle.org/
Redistribution and use of this software and associated documentation
("Software"), with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain copyright statements and
notices. Redistributions must also contain a copy of this document.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names "M/o/Vfuscator" and "Battelle" must not be used to endorse or
promote products derived from this Software without prior written
permission of Battelle Memorial Institute. For written permission,
please contact solutions@battelle.org
4. Products derived from this Software may not be called "M/o/Vfuscator" or
"Battelle", nor may "M/o/Vfuscator" or "Battelle" appear in their names
without prior written permission of Battelle Memorial Institute.
Battelle is a registered trademark of Battelle Memorial Institute.
5. Due credit should be given to the Battelle Memorial Institute.
THIS SOFTWARE IS PROVIDED BY BATTELLE MEMORIAL INSTITUTE "AS IS" AND ANY
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL BATTELLE MEMORIAL INSTITUTE OR ITS
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The original author of this software is Christopher P. Domas, an employee of
the Battelle Memorial Institute.

View file

@ -0,0 +1,3 @@
NAME = snake
SRCS = snake.c
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,188 @@
#include <stdlib.h>
#include <stdio.h>
#include <am.h>
#include <amdev.h>
#include <klib-macros.h>
#define MAX_LENGTH 100
#define TILE_W 8
typedef enum { NONE, UP, DOWN, LEFT, RIGHT } dir_t;
typedef struct {
int x, y;
} point_t;
typedef struct {
int width, height;
} dim_t;
typedef struct {
int top, bottom, left, right;
} rect_t;
typedef struct {
point_t body[MAX_LENGTH];
int length;
int index;
int dead;
} snake_t;
static void refresh() {
io_write(AM_GPU_FBDRAW, 0, 0, NULL, 0, 0, true);
}
static void draw_tile(int y, int x, uint32_t color) {
static uint32_t buf[TILE_W * TILE_W];
uint32_t last_color = 0xffffffff;
if (last_color != color) {
for (int i = 0; i < LENGTH(buf); i ++) { buf[i] = color; }
}
io_write(AM_GPU_FBDRAW, x * TILE_W, y * TILE_W, buf, TILE_W, TILE_W, false);
}
static int read_key() {
while (1) {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
if (ev.keydown || ev.keycode == AM_KEY_NONE) return ev.keycode;
}
}
static point_t create_food(dim_t game_size) {
point_t f;
f.x = rand() % game_size.width;
f.y = rand() % game_size.height;
return f;
}
static void print_board(rect_t board) {
uint32_t color = 0x0000ff00;
for (int i = board.left; i <= board.right; i++) {
draw_tile(board.top, i, color);
draw_tile(board.bottom, i, color);
}
for (int i = board.top; i <= board.bottom; i++) {
draw_tile(i, board.left, color);
draw_tile(i, board.right, color);
}
}
static void print_food(point_t food, rect_t board) {
draw_tile(food.y + board.top + 1, food.x + board.left + 1, 0x000000ff);
}
static void print_head(snake_t* snake, rect_t board) {
point_t *p = &snake->body[snake->index];
draw_tile(p->y + board.top + 1, p->x + board.left + 1, 0x00ff0000);
}
static void clear_tail(snake_t* snake, rect_t board) {
int t = snake->index-snake->length;
if (t < 0) { t += MAX_LENGTH; }
draw_tile(snake->body[t].y + board.top + 1, snake->body[t].x + board.left + 1, 0);
}
static dir_t get_dir(int c) {
switch (c) {
case AM_KEY_LEFT: return LEFT;
case AM_KEY_UP: return UP;
case AM_KEY_RIGHT: return RIGHT;
case AM_KEY_DOWN: return DOWN;
default: return NONE;
}
}
static void move_snake(snake_t* snake, dir_t dir) {
point_t p = snake->body[snake->index];
switch (dir) {
case LEFT: p.x --; break;
case DOWN: p.y ++; break;
case RIGHT: p.x ++; break;
case UP: p.y --; break;
default: break;
}
snake->index ++;
if (snake->index == MAX_LENGTH) { snake->index = 0; }
snake->body[snake->index] = p;
}
static int is_dead(snake_t* snake, dim_t game_size) {
point_t head = snake->body[snake->index];
if (head.x == -1) return 1;
if (head.x == game_size.width) return 1;
if (head.y == -1) return 1;
if (head.y == game_size.height) return 1;
for (int i = 1; i != snake->length; i ++) {
int j = snake->index-i;
if (j < 0) { j += MAX_LENGTH; }
if (head.x == snake->body[j].x && head.y == snake->body[j].y) { return 1; }
}
return 0;
}
static int has_food(snake_t* snake, point_t food) {
return snake->body[snake->index].x == food.x && snake->body[snake->index].y == food.y;
}
int main() {
snake_t snake = {0};
rect_t board;
dim_t screen;
dim_t game_size;
dir_t dir = RIGHT;
ioe_init();
screen.height = io_read(AM_GPU_CONFIG).height / TILE_W;
screen.width = io_read(AM_GPU_CONFIG).width / TILE_W;
game_size.width = screen.width - 2;
game_size.height = screen.height - 2;
snake.body[0].x = game_size.width / 2;
snake.body[0].y = game_size.height / 2;
snake.body[1].x = game_size.width / 2;
snake.body[1].y = game_size.height / 2 + 1;
snake.length = 2;
snake.index = 1;
board.left = screen.width / 2 - game_size.width / 2 - 1;
board.right = board.left + game_size.width + 1;
board.top = screen.height / 2 - game_size.height / 2 - 1;
board.bottom = board.top + game_size.height + 1;
print_board(board);
point_t food = create_food(game_size);
print_food(food, board);
do {
print_head(&snake, board);
clear_tail(&snake, board);
dir_t move_dir = get_dir(read_key());
switch (move_dir) {
case UP: if (dir != DOWN) dir = move_dir; break;
case DOWN: if (dir != UP) dir = move_dir; break;
case LEFT: if (dir != RIGHT) dir = move_dir; break;
case RIGHT: if (dir != LEFT) dir = move_dir; break;
default: break;
}
move_snake(&snake, dir);
snake.dead = is_dead(&snake, game_size);
if (has_food(&snake, food)) {
snake.length ++;
food = create_food(game_size);
print_food(food, board);
}
refresh();
uint64_t sleep = 100000 - snake.length * 5000 < 5000 ? 5000 : 100000 - snake.length * 5000;
uint64_t next_us = io_read(AM_TIMER_UPTIME).us + sleep;
while (io_read(AM_TIMER_UPTIME).us < next_us) ;
} while (!snake.dead);
printf("GAME OVER\nPress Q to Exit\n");
while (read_key() != AM_KEY_Q);
return 0;
}

View file

@ -0,0 +1,3 @@
NAME = thread-os
SRCS = thread-os.c
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,70 @@
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#define MAX_CPU 8
typedef union task {
struct {
const char *name;
union task *next;
void (*entry)(void *);
Context *context;
};
uint8_t stack[4096 * 3];
} Task;
Task *currents[MAX_CPU];
#define current currents[cpu_current()]
// user-defined tasks
int locked = 0;
void lock() { while (atomic_xchg(&locked, 1)); }
void unlock() { atomic_xchg(&locked, 0); }
void func(void *arg) {
while (1) {
lock();
printf("Thread-%s on CPU #%d\n", arg, cpu_current());
unlock();
for (int volatile i = 0; i < 100000; i++) ;
}
}
Task tasks[] = {
{ .name = "A", .entry = func },
{ .name = "B", .entry = func },
{ .name = "C", .entry = func },
{ .name = "D", .entry = func },
{ .name = "E", .entry = func },
};
// ------------------
Context *on_interrupt(Event ev, Context *ctx) {
extern Task tasks[];
if (!current) current = &tasks[0];
else current->context = ctx;
do {
current = current->next;
} while ((current - tasks) % cpu_count() != cpu_current());
return current->context;
}
void mp_entry() {
iset(true);
yield();
}
int main() {
cte_init(on_interrupt);
for (int i = 0; i < LENGTH(tasks); i++) {
Task *task = &tasks[i];
Area stack = (Area) { &task->context + 1, task + 1 };
task->context = kcontext(stack, task->entry, (void *)task->name);
task->next = &tasks[(i + 1) % LENGTH(tasks)];
}
mpe_init(mp_entry);
}

View file

@ -0,0 +1,3 @@
NAME = typing-game
SRCS = game.c font.c
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,28 @@
char font[] = {
0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x63, 0x63, 0x63, 0x7e, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x33, 0x61, 0x60, 0x60, 0x60, 0x60, 0x61, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x66, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x33, 0x63, 0x60, 0x60, 0x67, 0x63, 0x63, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x77, 0x7f, 0x6b, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x73, 0x6b, 0x67, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7b, 0x6f, 0x3e, 0x06, 0x03, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x63, 0x63, 0x63, 0x7e, 0x6c, 0x66, 0x66, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x7f, 0x77, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x22, 0x36, 0x1c, 0x1c, 0x36, 0x22, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x03, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00,
};

View file

@ -0,0 +1,178 @@
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#define FPS 30
#define CPS 5
#define CHAR_W 8
#define CHAR_H 16
#define NCHAR 128
#define COL_WHITE 0xeeeeee
#define COL_RED 0xff0033
#define COL_GREEN 0x00cc33
#define COL_PURPLE 0x2a0a29
enum { WHITE = 0, RED, GREEN, PURPLE };
struct character {
char ch;
int x, y, v, t;
} chars[NCHAR];
int screen_w, screen_h, hit, miss, wrong;
uint32_t texture[3][26][CHAR_W * CHAR_H], blank[CHAR_W * CHAR_H];
int min(int a, int b) {
return (a < b) ? a : b;
}
int randint(int l, int r) {
return l + (rand() & 0x7fffffff) % (r - l + 1);
}
void new_char() {
for (int i = 0; i < LENGTH(chars); i++) {
struct character *c = &chars[i];
if (!c->ch) {
c->ch = 'A' + randint(0, 25);
c->x = randint(0, screen_w - CHAR_W);
c->y = 0;
c->v = (screen_h - CHAR_H + 1) / randint(FPS * 3 / 2, FPS * 2);
c->t = 0;
return;
}
}
}
void game_logic_update(int frame) {
if (frame % (FPS / CPS) == 0) new_char();
for (int i = 0; i < LENGTH(chars); i++) {
struct character *c = &chars[i];
if (c->ch) {
if (c->t > 0) {
if (--c->t == 0) {
c->ch = '\0';
}
} else {
c->y += c->v;
if (c->y < 0) {
c->ch = '\0';
}
if (c->y + CHAR_H >= screen_h) {
miss++;
c->v = 0;
c->y = screen_h - CHAR_H;
c->t = FPS;
}
}
}
}
}
void render() {
static int x[NCHAR], y[NCHAR], n = 0;
for (int i = 0; i < n; i++) {
io_write(AM_GPU_FBDRAW, x[i], y[i], blank, CHAR_W, CHAR_H, false);
}
n = 0;
for (int i = 0; i < LENGTH(chars); i++) {
struct character *c = &chars[i];
if (c->ch) {
x[n] = c->x; y[n] = c->y; n++;
int col = (c->v > 0) ? WHITE : (c->v < 0 ? GREEN : RED);
io_write(AM_GPU_FBDRAW, c->x, c->y, texture[col][c->ch - 'A'], CHAR_W, CHAR_H, false);
}
}
io_write(AM_GPU_FBDRAW, 0, 0, NULL, 0, 0, true);
for (int i = 0; i < 40; i++) putch('\b');
printf("Hit: %d; Miss: %d; Wrong: %d", hit, miss, wrong);
}
void check_hit(char ch) {
int m = -1;
for (int i = 0; i < LENGTH(chars); i++) {
struct character *c = &chars[i];
if (ch == c->ch && c->v > 0 && (m < 0 || c->y > chars[m].y)) {
m = i;
}
}
if (m == -1) {
wrong++;
} else {
hit++;
chars[m].v = -(screen_h - CHAR_H + 1) / (FPS);
}
}
void video_init() {
screen_w = io_read(AM_GPU_CONFIG).width;
screen_h = io_read(AM_GPU_CONFIG).height;
extern char font[];
for (int i = 0; i < CHAR_W * CHAR_H; i++)
blank[i] = COL_PURPLE;
uint32_t blank_line[screen_w];
for (int i = 0; i < screen_w; i++)
blank_line[i] = COL_PURPLE;
for (int y = 0; y < screen_h; y ++)
io_write(AM_GPU_FBDRAW, 0, y, blank_line, screen_w, 1, false);
for (int ch = 0; ch < 26; ch++) {
char *c = &font[CHAR_H * ch];
for (int i = 0, y = 0; y < CHAR_H; y++)
for (int x = 0; x < CHAR_W; x++, i++) {
int t = (c[y] >> (CHAR_W - x - 1)) & 1;
texture[WHITE][ch][i] = t ? COL_WHITE : COL_PURPLE;
texture[GREEN][ch][i] = t ? COL_GREEN : COL_PURPLE;
texture[RED ][ch][i] = t ? COL_RED : COL_PURPLE;
}
}
}
char lut[256] = {
[AM_KEY_A] = 'A', [AM_KEY_B] = 'B', [AM_KEY_C] = 'C', [AM_KEY_D] = 'D',
[AM_KEY_E] = 'E', [AM_KEY_F] = 'F', [AM_KEY_G] = 'G', [AM_KEY_H] = 'H',
[AM_KEY_I] = 'I', [AM_KEY_J] = 'J', [AM_KEY_K] = 'K', [AM_KEY_L] = 'L',
[AM_KEY_M] = 'M', [AM_KEY_N] = 'N', [AM_KEY_O] = 'O', [AM_KEY_P] = 'P',
[AM_KEY_Q] = 'Q', [AM_KEY_R] = 'R', [AM_KEY_S] = 'S', [AM_KEY_T] = 'T',
[AM_KEY_U] = 'U', [AM_KEY_V] = 'V', [AM_KEY_W] = 'W', [AM_KEY_X] = 'X',
[AM_KEY_Y] = 'Y', [AM_KEY_Z] = 'Z',
};
int main() {
ioe_init();
video_init();
panic_on(!io_read(AM_TIMER_CONFIG).present, "requires timer");
panic_on(!io_read(AM_INPUT_CONFIG).present, "requires keyboard");
printf("Type 'ESC' to exit\n");
int current = 0, rendered = 0;
uint64_t t0 = io_read(AM_TIMER_UPTIME).us;
while (1) {
int frames = (io_read(AM_TIMER_UPTIME).us - t0) / (1000000 / FPS);
for (; current < frames; current++) {
game_logic_update(current);
}
while (1) {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
if (ev.keycode == AM_KEY_NONE) break;
if (ev.keydown && ev.keycode == AM_KEY_ESCAPE) halt(0);
if (ev.keydown && lut[ev.keycode]) {
check_hit(lut[ev.keycode]);
}
};
if (current > rendered) {
render();
rendered = current;
}
}
}

View file

@ -0,0 +1,3 @@
NAME = yield-os
SRCS = yield-os.c
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,31 @@
#include <am.h>
#include <klib-macros.h>
#define STACK_SIZE (4096 * 8)
typedef union {
uint8_t stack[STACK_SIZE];
struct { Context *cp; };
} PCB;
static PCB pcb[2], pcb_boot, *current = &pcb_boot;
static void f(void *arg) {
while (1) {
putch("?AB"[(uintptr_t)arg > 2 ? 0 : (uintptr_t)arg]);
for (int volatile i = 0; i < 100000; i++) ;
yield();
}
}
static Context *schedule(Event ev, Context *prev) {
current->cp = prev;
current = (current == &pcb[0] ? &pcb[1] : &pcb[0]);
return current->cp;
}
int main() {
cte_init(schedule);
pcb[0].cp = kcontext((Area) { pcb[0].stack, &pcb[0] + 1 }, f, (void *)1L);
pcb[1].cp = kcontext((Area) { pcb[1].stack, &pcb[1] + 1 }, f, (void *)2L);
yield();
panic("Should not reach here!");
}