Skip to content

Commit

Permalink
Support for mode 7 text colors in the VDU
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Jul 30, 2021
1 parent d741cf5 commit 19caa5a
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

bbz
dist/
62 changes: 37 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ References:
- Applecorn source code: https://github.com/bobbimanners/Applecorn

## Features
Not all of the MOS entrypoints are defined and it ignores the VDU control codes.
Can run BBC BASIC, including load and save, and most of the language ROMs.
- Some of the MOS entrypoints and VDU control codes are defined.
- Can run BBC BASIC and most of the language ROMs.
- Saves and loads files from the host filesystem.
- Does some of the mode 7 text coloring using ANSI escape codes on the terminal. Try `VDU 65,129,66,130,67,132,68,135,69,13,10` on BBC BASIC.

## Usage

Expand All @@ -50,40 +52,50 @@ Running BBC Basic:
$ ./bbz
bbz - Acorn MOS for 6502 adaptation layer, https://github.com/ivanizag/bbz
BASIC - (C)1982 Acorn
>PRINT "HELLO"
HELLO
>10 A=12
>20 PRINT A
>LIST
10 A=12
20 PRINT A
>10 PRINT "HEY"
>RUN
12
>HEY
HEY
>SAVE "TEST"
>NEW
>LOAD "TEST"
>LIST
10 PRINT "HEY"
>X
Mistake
>^C
$
>^Csignal: interrupt
$ ls -l TEST
-rw-r--r-- 1 casa casa 14 jul 30 20:04 TEST
```

Log of the MOS calls (excluding the most verbose output API calls):
```
$ ./bbz -m
$ ./bbz -m ROMs/Forth_103.rom
bbz - Acorn MOS for 6502 adaptation layer, https://github.com/ivanizag/bbz
[[[OSBYTE84('Read top of user mem',X=0x00,Y=0x00)]]]
[[[OSBYTE83('Read bottom of user mem',X=0x00,Y=0x80)]]]
>PRINT "HELLO"
[[[OSWORD00('read line',BUF=0x0700)='PRINT "HELLO"']]]
HELLO
>HEY
[[[OSWORD00('read line',BUF=0x0700)='HEY']]]
[[[BREAK(ERR=04, 'Mistake']]]
[[[OSBYTEda('R/W number of items in VDU',X=0x00,Y=0x00)]]]
[[[OSBYTE7e('Ack detection of an ESC condition',X=0x00,Y=0x00)]]]
FORTH - (C) Acornsoft Ltd. 1983
COLD or WARM start (C/W)? C
[[[OSRDCH()=0x43]]]
[[[OSARGS('Get fiing system',A=00,Y=00)= 4]]]
[[[OSBYTE82('Read machine high order address',X=0x58,Y=0x00) => (X=0xff,Y=0xff)]]]
[[[OSBYTE84('Read top of user mem',X=0x58,Y=0x00) => (X=0x00,Y=0x80)]]]
[[[OSBYTE83('Read bottom of user mem',X=0x58,Y=0x00) => (X=0x00,Y=0x0e)]]]
FORTH
OK
2 1 + .
[[[OSWORD00('read line',BUF=0x0542,range=20-ff, maxlen=80)='2 1 + .']]]
3 OK
Mistake
>^C
$
```

Using mode 7 colors:

![mode 7 colors](doc/vdu_colors.png)

2 changes: 1 addition & 1 deletion bbz.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func RunMOSEnvironment(romFilename string, cpuLog bool, apiLog bool, apiLogIO bo
/*
This call issues an LF CR to the currently selected output stream.
*/
fmt.Println()
env.vdu.writeNewline()
env.logIO("OSNEWL()")

case 0xffee: // OSWRCH
Expand Down
Binary file added doc/vdu_colors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions osWord.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func execOSWORD(env *environment) {
env.putStringInMem(buffer, line+"\r", maxLength)
pOut := p &^ 1 // Clear carry
env.cpu.SetAXYP(1, x, uint8(len(line)), pOut)
env.vdu.mode7Reset()

env.log(fmt.Sprintf("OSWORD00('read line',BUF=0x%04x,range=%02x-%02x, maxlen=%v)='%s'",
buffer, minChar, maxChar, maxLength, line))
Expand Down
83 changes: 74 additions & 9 deletions vdu.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ import "fmt"
type vdu struct {
queue []uint8

mode uint8
mode uint8

// Mode 0-6
textColour uint8
graphColour uint8

// Mode 7
m7fgColour uint8
m7bgColour uint8
m7Flash bool

// Toogles
printer bool // VDU2 and VDU3
textOnGr bool // VDU5 and VDU4
Expand Down Expand Up @@ -36,6 +43,7 @@ func newVdu() *vdu {
var v vdu
// Mode 7 on startup
v.mode = 7
v.m7fgColour = 7 // white

return &v
}
Expand Down Expand Up @@ -68,6 +76,7 @@ func (v *vdu) write(i uint8) {
if argsNeeded[v.queue[0]] == len(v.queue)-1 {
// We have enough args
v.exec(v.queue[0], v.queue[1:])
v.queue = nil
}
}
}
Expand Down Expand Up @@ -160,7 +169,8 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
cursor is already on the bottom line then the whole display will normally be
moved up one line.
*/
out = "\x1b[B" // Not the normal \n, here we need \r\n
//out = "\x1b[B" // Not the normal \n, here we need \r\n
out = v.mode7ResetCode() + string(cmd)
case 11:
/*
This code (VDU11 or CTRL K) moves the text cursor up one line. If the cursor
Expand All @@ -174,15 +184,15 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
statement CLS has exactly the same effect as VDU12, or CTRL L. This code also
moves the text cursor to the top left of the text window.
*/
out = "\x1b[2J\x1b[H"
out = v.mode7ResetCode() + "\x1b[2J\x1b[H"
case 13:
/*
This code is produced by the RETURN key. However, its effect on the screen
display if issued as a VDU13 or PRINT CHR$(13);is to move the text cursor to
the left hand edge of the current text line (but within the current text window, of
course).
*/
out = string(cmd)
out = v.mode7ResetCode() + string(cmd)
case 14:
/*
This code makes the screen display wait at the bottom of each page. It is
Expand Down Expand Up @@ -303,7 +313,7 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
does not change HIMEM).
*/
v.mode = q[0]
fmt.Printf("<<Changed to mode %v>>", v.mode)
out = v.mode7ResetCode()
case 23:
/*
This code is used to reprogram displayed characters. The ASCII code assigns
Expand Down Expand Up @@ -353,7 +363,7 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
sets the graphics origin to the bottom left of the screen. In this state it is possible
to write text and to draw graphics anywhere on the screen.
*/
out = "\x1b[H"
out = v.mode7ResetCode() + "\x1b[H"
// TODO: graphics reset
case 27:
/*
Expand Down Expand Up @@ -393,7 +403,7 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
This code (VDU30 or CTRL ^) moves the text cursor to the top left of the text
area.
*/
out = "\x1b[H"
out = v.mode7ResetCode() + "\x1b[H"
case 31:
/*
The code VDU31 enables the text cursor to be moved to any character position
Expand All @@ -414,11 +424,42 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
key.
*/
out = "\x1b[D \x1b[D"

default:
if v.mode == 7 {
// TODO: process MODE7 control codes
out = adjustAsciiMode7(cmd)
/*
The order of colors is: black, red, green, yellow, blue, magenta,
cyan and white for mmode 7 and for ANSI.
Red is:
- 129 as control code
. 1 as m7fgColour and m7bgColour
. 31 as ANSI fg color
- 41 as ANSI bg color
*/
switch {
case 129 <= cmd && cmd <= 135: // Text colors
v.m7fgColour = cmd - 129 + 1
out = fmt.Sprintf("\x1b[%vm ", v.m7fgColour+30)
case cmd == 136: // Flash
v.m7Flash = true
out = "\x1b[5m "
case cmd == 137: // Steady (not flash)
v.m7Flash = false
out = "\x1b[25m "
case cmd == 156: // Black background
v.m7bgColour = 0
out = fmt.Sprintf("\x1b[%vm ", v.m7bgColour+40)
case cmd == 157: // New background
v.m7bgColour = v.m7fgColour
out = fmt.Sprintf("\x1b[%vm ", v.m7bgColour+40)
case 128 <= cmd && cmd <= 159: // Rest
out = " "
default:
out = adjustAsciiMode7(cmd)
}

} else {
// Modes 0 to 6
switch {
case 32 <= cmd && cmd <= 126:
/*
Expand Down Expand Up @@ -450,6 +491,30 @@ func (v *vdu) exec(cmd uint8, q []uint8) {
}
}

func (v *vdu) mode7ResetCode() string {
if v.mode != 7 {
return ""
}
out := ""
if v.m7fgColour != 7 /* white */ {
out += "\x1b[37m"
v.m7fgColour = 7
}
if v.m7bgColour != 0 /* black */ {
out += "\x1b[40m"
v.m7bgColour = 0
}
if v.m7Flash {
out += "\x1b[25m"
v.m7Flash = false
}
return out
}

func (v *vdu) mode7Reset() {
fmt.Print(v.mode7ResetCode())
}

func adjustAscii(ch uint8) string {
// Some chars are different from standard ASCII
// See: http://beebwiki.mdfs.net/ASCII
Expand Down

0 comments on commit 19caa5a

Please sign in to comment.