2019-04-25 05:19:47 +00:00
|
|
|
#include <stdio.h>
|
2022-06-21 00:52:54 +00:00
|
|
|
#include <stdlib.h>
|
2022-06-29 03:41:26 +00:00
|
|
|
#include <string.h>
|
2019-04-25 05:19:47 +00:00
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
#include "lcd.h"
|
|
|
|
|
2022-07-21 03:21:36 +00:00
|
|
|
void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit)
|
2019-10-22 06:30:19 +00:00
|
|
|
{
|
2022-08-03 07:08:28 +00:00
|
|
|
lcd_write(lcd, addr, lcd_read(lcd, addr) | bit);
|
2019-10-22 06:30:19 +00:00
|
|
|
}
|
|
|
|
|
2022-07-21 03:21:36 +00:00
|
|
|
void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit)
|
2019-10-22 06:30:19 +00:00
|
|
|
{
|
2022-08-03 07:08:28 +00:00
|
|
|
lcd_write(lcd, addr, lcd_read(lcd, addr) & ~bit);
|
2019-10-22 06:30:19 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 03:55:13 +00:00
|
|
|
int lcd_isset(struct lcd *lcd, u16 addr, u8 bit)
|
|
|
|
{
|
|
|
|
u8 val = lcd_read(lcd, addr);
|
2022-08-03 07:08:28 +00:00
|
|
|
return val & bit;
|
2022-07-26 03:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lcd_set_mode(struct lcd *lcd, int mode)
|
|
|
|
{
|
|
|
|
u8 val = lcd_read(lcd, REG_STAT);
|
|
|
|
lcd_write(lcd, REG_STAT, (val & 0xfc) | mode);
|
|
|
|
}
|
|
|
|
|
2022-06-21 00:52:54 +00:00
|
|
|
void lcd_new(struct lcd *lcd)
|
|
|
|
{
|
2022-06-29 03:41:26 +00:00
|
|
|
lcd->buf = malloc(256 * 256);
|
2022-07-21 03:21:36 +00:00
|
|
|
memset(lcd->buf, 0, 256 * 256);
|
2022-06-21 00:52:54 +00:00
|
|
|
// todo < 8 bpp
|
|
|
|
lcd->pixels = malloc(LCD_WIDTH * LCD_HEIGHT);
|
|
|
|
}
|
|
|
|
|
2019-10-22 06:30:19 +00:00
|
|
|
u8 lcd_is_valid_addr(u16 addr)
|
|
|
|
{
|
2022-06-29 03:41:26 +00:00
|
|
|
return (addr >= 0xfe00 && addr < 0xfea0) || (addr >= REG_LCD_BASE && addr <= REG_LCD_LAST);
|
2019-10-22 06:30:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 lcd_read(struct lcd *lcd, u16 addr)
|
|
|
|
{
|
2022-06-29 03:41:26 +00:00
|
|
|
if (addr >= 0xfe00 && addr < 0xfea0) {
|
|
|
|
return lcd->oam[addr - 0xfe00];
|
|
|
|
}
|
2019-10-22 06:30:19 +00:00
|
|
|
return lcd->regs[addr - REG_LCD_BASE];
|
|
|
|
}
|
|
|
|
|
|
|
|
void lcd_write(struct lcd *lcd, u16 addr, u8 value)
|
|
|
|
{
|
2022-06-29 03:41:26 +00:00
|
|
|
if (addr >= 0xfe00 && addr < 0xfea0) {
|
|
|
|
lcd->oam[addr - 0xfe00] = value;
|
|
|
|
} else {
|
|
|
|
lcd->regs[addr - REG_LCD_BASE] = value;
|
|
|
|
}
|
2019-10-22 06:30:19 +00:00
|
|
|
}
|
|
|
|
|
2019-04-25 05:19:47 +00:00
|
|
|
void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value)
|
|
|
|
{
|
|
|
|
if (x >= LCD_WIDTH || y >= LCD_HEIGHT) {
|
|
|
|
printf("warning: trying to write to (%d, %d) outside of lcd bounds\n", x, y);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lcd->pixels[y * LCD_WIDTH + x] = value;
|
2019-10-22 06:30:19 +00:00
|
|
|
}
|
|
|
|
|
2022-08-02 05:51:26 +00:00
|
|
|
void lcd_apply_scroll(struct lcd *lcd)
|
2022-06-29 03:41:26 +00:00
|
|
|
{
|
2022-08-02 05:51:26 +00:00
|
|
|
int scroll_y = lcd_read(lcd, REG_SCY);
|
|
|
|
int scroll_x = lcd_read(lcd, REG_SCX);
|
|
|
|
|
|
|
|
int lines;
|
|
|
|
for (lines = 0; lines < 144; lines++) {
|
|
|
|
int src_y = (scroll_y + lines) & 0xff;
|
|
|
|
int cols;
|
|
|
|
for (cols = 0; cols < 160; cols++) {
|
|
|
|
int src_off = (src_y << 8) + ((scroll_x + cols) & 0xff);
|
|
|
|
lcd->pixels[lines * 160 + cols] = lcd->buf[src_off];
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 03:41:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int lcd_step(struct lcd *lcd)
|
2019-10-22 06:30:19 +00:00
|
|
|
{
|
|
|
|
// step to next scanline 0-153
|
|
|
|
u8 next_scanline = (lcd_read(lcd, REG_LY) + 1) % 154;
|
|
|
|
lcd_write(lcd, REG_LY, next_scanline);
|
2022-06-29 03:41:26 +00:00
|
|
|
|
|
|
|
return next_scanline;
|
2022-06-21 00:46:32 +00:00
|
|
|
// printf("update lcd %d\n", next_scanline);
|
2019-04-25 05:19:47 +00:00
|
|
|
}
|