#include <sys/param.h>
#include <luna68k/stand/boot/samachdep.h>
#include <machine/board.h>
union bmd_rfcnt {
struct {
int16_t rfc_hcnt;
int16_t rfc_vcnt;
} p;
uint32_t u;
};
#define isprint(c) ((c) >= 0x20 && (c) < 0x7f)
#define BMAP_OFFSET 8
#define PB_WIDTH 2048
#define PB_HEIGHT 1024
#define PL_WIDTH 64
#define PS_WIDTH 128
#define P_WIDTH 256
#define SB_WIDTH 1280
#define SB_HEIGHT 1024
#define SL_WIDTH 40
#define S_WIDTH 160
#define FB_WIDTH 12
#define FB_HEIGHT 20
#define NEXT_LINE(addr) (addr + (PL_WIDTH * FB_HEIGHT))
#define SKIP_NEXT_LINE(addr) (addr += (PL_WIDTH - SL_WIDTH))
static void bmd_draw_char(uint8_t *, uint8_t *, int, int, int);
static void bmd_reverse_char(uint8_t *, uint8_t *, int, int);
static void bmd_erase_char(uint8_t *, uint8_t *, int, int);
static void bmd_erase_screen(volatile uint32_t *);
static void bmd_scroll_screen(volatile uint32_t *, volatile uint32_t *,
int, int, int, int);
struct bmd_linec {
struct bmd_linec *bl_next;
struct bmd_linec *bl_prev;
int bl_col;
int bl_end;
uint8_t bl_line[128];
};
struct bmd_softc {
int bc_stat;
uint8_t *bc_raddr;
uint8_t *bc_waddr;
int bc_xmin;
int bc_xmax;
int bc_ymin;
int bc_ymax;
int bc_col;
int bc_row;
struct bmd_linec *bc_bl;
char bc_escseq[8];
char *bc_esc;
void (*bc_escape)(int);
};
#define STAT_NORMAL 0x0000
#define STAT_ESCAPE 0x0001
#define STAT_INSERT 0x0100
static struct bmd_softc bmd_softc;
static struct bmd_linec bmd_linec[52];
static void bmd_escape(int);
static void bmd_escape_0(int);
#if 0
static void bmd_escape_1(int);
#endif
static void
bmd_escape(int c)
{
struct bmd_softc *bp = &bmd_softc;
switch (c) {
case '[':
bp->bc_escape = bmd_escape_0;
break;
default:
bp->bc_stat &= ~STAT_ESCAPE;
bp->bc_esc = &bp->bc_escseq[0];
bp->bc_escape = bmd_escape;
break;
}
}
static void
bmd_escape_0(int c)
{
struct bmd_softc *bp = &bmd_softc;
struct bmd_linec *bq = bp->bc_bl;
switch (c) {
case 'A':
if (bp->bc_row > bp->bc_ymin) {
bp->bc_row--;
}
break;
case 'C':
if (bq->bl_col < bp->bc_xmax - 1) {
bq->bl_col++;
}
break;
case 'K':
if (bq->bl_col < bp->bc_xmax) {
int col;
for (col = bq->bl_col; col < bp->bc_xmax; col++)
bmd_erase_char(bp->bc_raddr,
bp->bc_waddr,
col, bp->bc_row);
}
bq->bl_end = bq->bl_col;
break;
case 'H':
bq->bl_col = bq->bl_end = bp->bc_xmin;
bp->bc_row = bp->bc_ymin;
break;
default:
#if 0
*bp->bc_esc++ = c;
bp->bc_escape = bmd_escape_1;
return;
#endif
break;
}
bp->bc_stat &= ~STAT_ESCAPE;
bp->bc_esc = &bp->bc_escseq[0];
bp->bc_escape = bmd_escape;
}
#if 0
static void
bmd_escape_1(int c)
{
struct bmd_softc *bp = &bmd_softc;
struct bmd_linec *bq = bp->bc_bl;
int col = 0, row = 0;
char *p;
switch (c) {
case 'J':
bp->bc_stat &= ~STAT_ESCAPE;
bp->bc_esc = &bp->bc_escseq[0];
bp->bc_escape = bmd_escape;
break;
case 'H':
for (p = &bp->bc_escseq[0]; *p != ';'; p++)
row = (row * 10) + (*p - 0x30);
p++;
for (p = &bp->bc_escseq[0]; p != bp->bc_esc; p++)
col = (col * 10) + (*p - 0x30);
bq->bl_col = col + bp->bc_xmin;
bp->bc_row = row + bp->bc_ymin;
bp->bc_stat &= ~STAT_ESCAPE;
bp->bc_esc = &bp->bc_escseq[0];
bp->bc_escape = bmd_escape;
break;
default:
*bp->bc_esc++ = c;
break;
}
}
#endif
void
bmdinit(void)
{
volatile uint32_t *bmd_rfcnt = (uint32_t *)BMAP_RFCNT;
volatile uint32_t *bmd_bmsel = (uint32_t *)BMAP_BMSEL;
struct bmd_softc *bp = &bmd_softc;
struct bmd_linec *bq;
int i;
union bmd_rfcnt rfcnt;
bp->bc_raddr = (uint8_t *)(BMAP_BMAP0 + BMAP_OFFSET);
bp->bc_waddr = (uint8_t *)(BMAP_BMP + BMAP_OFFSET);
rfcnt.p.rfc_hcnt = 7;
rfcnt.p.rfc_vcnt = -27;
*bmd_rfcnt = rfcnt.u;
bp->bc_stat = STAT_NORMAL;
bp->bc_xmin = 8;
bp->bc_xmax = 96;
bp->bc_ymin = 2;
bp->bc_ymax = 48;
bp->bc_row = bp->bc_ymin;
for (i = bp->bc_ymin; i < bp->bc_ymax; i++) {
bmd_linec[i].bl_next = &bmd_linec[i + 1];
bmd_linec[i].bl_prev = &bmd_linec[i - 1];
}
bmd_linec[bp->bc_ymax - 1].bl_next = &bmd_linec[bp->bc_ymin];
bmd_linec[bp->bc_ymin].bl_prev = &bmd_linec[bp->bc_ymax - 1];
bq = bp->bc_bl = &bmd_linec[bp->bc_ymin];
bq->bl_col = bq->bl_end = bp->bc_xmin;
bp->bc_col = bp->bc_xmin;
bp->bc_esc = &bp->bc_escseq[0];
bp->bc_escape = bmd_escape;
*bmd_bmsel = 0xff;
bmd_erase_screen((uint32_t *)bp->bc_waddr);
*bmd_bmsel = 0x01;
bmd_reverse_char(bp->bc_raddr,
bp->bc_waddr,
bq->bl_col, bp->bc_row);
}
void
bmdadjust(int16_t hcnt, int16_t vcnt)
{
volatile uint32_t *bmd_rfcnt = (uint32_t *)BMAP_RFCNT;
union bmd_rfcnt rfcnt;
printf("bmdadjust: hcnt = %d, vcnt = %d\n", hcnt, vcnt);
rfcnt.p.rfc_hcnt = hcnt;
rfcnt.p.rfc_vcnt = vcnt;
*bmd_rfcnt = rfcnt.u;
}
int
bmdputc(int c)
{
struct bmd_softc *bp = &bmd_softc;
struct bmd_linec *bq = bp->bc_bl;
int i;
c &= 0x7F;
bmd_reverse_char(bp->bc_raddr,
bp->bc_waddr,
bq->bl_col, bp->bc_row);
if (bp->bc_stat & STAT_ESCAPE) {
*bp->bc_esc++ = c;
(*bp->bc_escape)(c);
goto done;
}
if (isprint(c)) {
bmd_draw_char(bp->bc_raddr, bp->bc_waddr,
bq->bl_col, bp->bc_row, c);
bq->bl_col++;
bq->bl_end++;
if (bq->bl_col >= bp->bc_xmax) {
bq->bl_col = bq->bl_end = bp->bc_xmin;
bp->bc_row++;
if (bp->bc_row >= bp->bc_ymax) {
bmd_scroll_screen((uint32_t *)bp->bc_raddr,
(uint32_t *)bp->bc_waddr,
bp->bc_xmin, bp->bc_xmax,
bp->bc_ymin, bp->bc_ymax);
bp->bc_row = bp->bc_ymax - 1;
}
}
} else {
switch (c) {
case 0x08:
if (bq->bl_col > bp->bc_xmin) {
bq->bl_col--;
}
break;
case 0x09:
case 0x0B:
i = ((bq->bl_col / 8) + 1) * 8;
if (i < bp->bc_xmax) {
bq->bl_col = bq->bl_end = i;
}
break;
case 0x0A:
bp->bc_row++;
if (bp->bc_row >= bp->bc_ymax) {
bmd_scroll_screen((uint32_t *)bp->bc_raddr,
(uint32_t *)bp->bc_waddr,
bp->bc_xmin, bp->bc_xmax,
bp->bc_ymin, bp->bc_ymax);
bp->bc_row = bp->bc_ymax - 1;
}
break;
case 0x0D:
bq->bl_col = bp->bc_xmin;
break;
case 0x1B:
bp->bc_stat |= STAT_ESCAPE;
*bp->bc_esc++ = 0x1b;
break;
case 0x7F:
if (bq->bl_col > bp->bc_xmin) {
bq->bl_col--;
bmd_erase_char(bp->bc_raddr,
bp->bc_waddr,
bq->bl_col, bp->bc_row);
}
break;
default:
break;
}
}
done:
bmd_reverse_char(bp->bc_raddr,
bp->bc_waddr,
bq->bl_col, bp->bc_row);
return c;
}
void
bmdclear(void)
{
struct bmd_softc *bp = &bmd_softc;
struct bmd_linec *bq = bp->bc_bl;
bmd_erase_screen((uint32_t *)bp->bc_waddr);
bq->bl_col = bq->bl_end = bp->bc_xmin;
bp->bc_row = bp->bc_ymin;
bmd_reverse_char(bp->bc_raddr,
bp->bc_waddr,
bq->bl_col, bp->bc_row);
}
static void
bmd_draw_char(uint8_t *raddr, uint8_t *waddr, int col, int row, int c)
{
volatile uint16_t *p, *q;
volatile uint32_t *lp, *lq;
const uint16_t *fp;
int i;
fp = &bmdfont[c][0];
switch (col % 4) {
case 0:
p = (uint16_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
q = (uint16_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
for (i = 0; i < FB_HEIGHT; i++) {
*q = (*p & 0x000F) | (*fp & 0xFFF0);
p += 128;
q += 128;
fp++;
}
break;
case 1:
lp = (uint32_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
lq = (uint32_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
for (i = 0; i < FB_HEIGHT; i++) {
*lq = (*lp & 0xFFF000FF) |
((uint32_t)(*fp & 0xFFF0) << 4);
lp += 64;
lq += 64;
fp++;
}
break;
case 2:
lp = (uint32_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 2);
lq = (uint32_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 2);
for (i = 0; i < FB_HEIGHT; i++) {
*lq = (*lp & 0xFF000FFF) |
((uint32_t)(*fp & 0xFFF0) << 8);
lp += 64;
lq += 64;
fp++;
}
break;
case 3:
p = (uint16_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 4);
q = (uint16_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 4);
for (i = 0; i < FB_HEIGHT; i++) {
*q = (*p & 0xF000) | ((*fp & 0xFFF0) >> 4);
p += 128;
q += 128;
fp++;
}
break;
default:
break;
}
}
static void
bmd_reverse_char(uint8_t *raddr, uint8_t *waddr, int col, int row)
{
volatile uint16_t *p, *q;
volatile uint32_t *lp, *lq;
int i;
switch (col % 4) {
case 0:
p = (uint16_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
q = (uint16_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
for (i = 0; i < FB_HEIGHT; i++) {
*q = (*p & 0x000F) | (~(*p) & 0xFFF0);
p += 128;
q += 128;
}
break;
case 1:
lp = (uint32_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
lq = (uint32_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6));
for (i = 0; i < FB_HEIGHT; i++) {
*lq = (*lp & 0xFFF000FF) | (~(*lp) & 0x000FFF00);
lp += 64;
lq += 64;
}
break;
case 2:
lp = (uint32_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 2);
lq = (uint32_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 2);
for (i = 0; i < FB_HEIGHT; i++) {
*lq = (*lp & 0xFF000FFF) | (~(*lp) & 0x00FFF000);
lp += 64;
lq += 64;
}
break;
case 3:
p = (uint16_t *)(raddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 4);
q = (uint16_t *)(waddr + ((row * FB_HEIGHT) << 8)
+ ((col / 4) * 6) + 4);
for (i = 0; i < FB_HEIGHT; i++) {
*q = (*p & 0xF000) | (~(*p) & 0x0FFF);
p += 128;
q += 128;
}
break;
default:
break;
}
}
static void
bmd_erase_char(uint8_t *raddr, uint8_t *waddr, int col, int row)
{
bmd_draw_char(raddr, waddr, col, row, 0);
}
static void
bmd_erase_screen(volatile uint32_t *lp)
{
int i, j;
for (i = 0; i < SB_HEIGHT; i++) {
for (j = 0; j < SL_WIDTH; j++)
*lp++ = 0;
SKIP_NEXT_LINE(lp);
}
}
static void
bmd_scroll_screen(volatile uint32_t *lp, volatile uint32_t *lq,
int xmin, int xmax, int ymin, int ymax)
{
int i, j;
lp += ((PL_WIDTH * FB_HEIGHT) * (ymin + 1));
lq += ((PL_WIDTH * FB_HEIGHT) * ymin);
for (i = 0; i < ((ymax - ymin -1) * FB_HEIGHT); i++) {
for (j = 0; j < SL_WIDTH; j++) {
*lq++ = *lp++;
}
lp += (PL_WIDTH - SL_WIDTH);
lq += (PL_WIDTH - SL_WIDTH);
}
for (i = 0; i < FB_HEIGHT; i++) {
for (j = 0; j < SL_WIDTH; j++) {
*lq++ = 0;
}
lq += (PL_WIDTH - SL_WIDTH);
}
}