Back to Hardware

Friday, 1st August 2008

I enjoy dabbling with low-level programming, but have never actually built a computer to run these programs. I think it's time to correct that, and as the BBC BASIC project has required me to develop an almost complete Z80 OS (the only thing that's left for the TI-OS to do is manage files) I thought a Z80 computer would be a good start.

The planned specs are (as a starting point):

  • 10 MHz Z80180 CPU;
  • 64KB RAM (2 32K×8 SRAM chips);
  • 128KB Flash ROM;
  • Graphical LCD;
  • Simple joypad input;
  • Keyboard input (AT using either software AT routines or dedicated microcontroller).

The first spanner in the works is the Z80180, as I didn't read the datasheet closely enough and it's in a DIP 64 package with 0.07" pin spacing instead of the standard 0.1" pin spacing. I'll need to find some way of constructing an adapter so I can use it with my breadboards and stripboard. smile.gif

In the meantime, I've concentrated on the graphical LCD. I picked a 128×64 backlit graphical LCD for the princely sum of £16. It's very easy to control - you hook up it up to a 8-bit data bus to transfer image data and instructions and a handful of control pins to indicate what you're doing on that bus (reading or writing, whether you're sending an instruction or some image data, that sort of thing) and that's it - the only supporting circuitry it requires is a 10K potentiometer to act as a contrast control and power for the display and backlight.

2008.08.01.01.LCD.Hello.jpg

To experiment with the LCD, I'm using a PICAXE-28X1 microcontroller, programmed in BASIC. There isn't much space to store graphics, so I'm using a 32 character font (at eight bytes per character, that takes up all 256 bytes of free EEPROM space!)

; LCD data bus should be connected to port C.

Symbol LcdRegisterSelection = 0 ; D/I  :  4
Symbol LcdReadWrite         = 1 ; R/W  :  5
Symbol LcdStartEnable       = 2 ; E    :  6
Symbol LcdChipSelect1       = 3 ; CS1  : 15
Symbol LcdChipSelect2       = 4 ; CS2  : 16
Symbol LcdReset             = 5 ; /RST : 17

; Storage for console state variables.

Symbol ConsoleX             = B10
Symbol ConsoleY             = B11
Symbol ConsoleChar          = B12


	GoSub LcdInit                              ; Initialise LCD.
	B0 = %00111111 : GoSub LcdWriteInstruction ; Switch LCD on.

	GoSub LcdClear ; Clear LCD
	
	; Write the obligatory message to the LCD.
	
	ConsoleX = 0 : ConsoleY = 0

	ConsoleChar = $08 : GoSub LcdPutChar ; H
	ConsoleChar = $05 : GoSub LcdPutChar ; E
	ConsoleChar = $0C : GoSub LcdPutChar ; L
	ConsoleChar = $0C : GoSub LcdPutChar ; L
	ConsoleChar = $0F : GoSub LcdPutChar ; O
	ConsoleChar = $1D : GoSub LcdPutChar ; ,
	ConsoleChar = $00 : GoSub LcdPutChar ;  
	ConsoleChar = $17 : GoSub LcdPutChar ; W
	ConsoleChar = $0F : GoSub LcdPutChar ; O
	ConsoleChar = $12 : GoSub LcdPutChar ; R
	ConsoleChar = $0C : GoSub LcdPutChar ; L
	ConsoleChar = $04 : GoSub LcdPutChar ; D
	ConsoleChar = $1B : GoSub LcdPutChar ; !
	
	Pause 2000
	
	B2 = 0	
MainLoop:
	B2 = B2 - 1
	B0 = B2
	GoSub LcdGotoZ
	Pause 30
	GoTo MainLoop

LcdInit:
	DirsC = $00               ; Set data bus to input.
	High LcdStartEnable       ; We're not writing anything.
	High LcdChipSelect1
	High LcdChipSelect2
	Low LcdReset
	Pause 500
	High LcdReset
	Pause 500
	Return

LcdWriteInstruction:
	Low LcdReadWrite
	DirsC = $FF               ; Data bus = output.
	PinsC = B0                ; Set data bus state.
	Low LcdRegisterSelection  ; Instruction, not data.
	Low LcdStartEnable
	High LcdStartEnable
	DirsC = $00               ; Leave data bus floating.
	Return

LcdWriteData:
	Low LcdReadWrite
	DirsC = $FF               ; Data bus = output.
	PinsC = B0                ; Set data bus state.
	High LcdRegisterSelection ; Data, not instruction.	
	Low LcdStartEnable
	High LcdStartEnable
	DirsC = $00               ; Leave data bus floating.
	Return

LcdGotoX:
	B0 = B0 And 7
	B0 = B0 + %10111000
	GoTo LcdWriteInstruction
	
LcdGotoY:
	B0 = B0 And 63
	B0 = B0 + %01000000
	GoTo LcdWriteInstruction

LcdGotoZ:
	B0 = B0 And 63
	B0 = B0 + %11000000
	GoTo LcdWriteInstruction

LcdClear:
	For B2 = 0 To 7
		B0 = B2
		GoSub LcdGotoX
		B0 = 0
		GoSub LcdGotoY
		B0 = 0
		For B3 = 0 To 63
			GoSub LcdWriteData
		Next
	Next B2
	Return

LcdPutMap:
	B1 = B0 * 8
	For B2 = 0 To 7
		Read B1, B0
		GoSub LcdWriteData
		B1 = B1 + 1
	Next B2
	Return

LcdPutChar:
	B0 = ConsoleY
	GoSub LcdGotoX
	B0 = ConsoleX * 8
	If B0 < 64 Then
		Low LcdChipSelect2
	Else
		Low LcdChipSelect1
		B0 = B0 - 64
	EndIf
	GoSub LcdGotoY
	B0 = ConsoleChar
	GoSub LcdPutMap
	High LcdChipSelect1
	High LcdChipSelect2
	ConsoleX = ConsoleX + 1
	If ConsoleX = 16 Then
		ConsoleX = 0
		ConsoleY = ConsoleY + 1
		If ConsoleY = 8 Then
			ConsoleY = 0
		EndIf
	EndIf
	Return
	
; Font
EEPROM $00,($00,$00,$00,$00,$00,$00,$00,$00,$7E,$7F,$09,$09,$7F,$7E,$00,$00)
EEPROM $10,($7F,$7F,$49,$49,$7F,$36,$00,$00,$3E,$7F,$41,$41,$63,$22,$00,$00)
EEPROM $20,($7F,$7F,$41,$63,$3E,$1C,$00,$00,$7F,$7F,$49,$49,$49,$41,$00,$00)
EEPROM $30,($7F,$7F,$09,$09,$09,$01,$00,$00,$3E,$7F,$41,$49,$7B,$3A,$00,$00)
EEPROM $40,($7F,$7F,$08,$08,$7F,$7F,$00,$00,$41,$41,$7F,$7F,$41,$41,$00,$00)
EEPROM $50,($20,$61,$41,$7F,$3F,$01,$00,$00,$7F,$7F,$1C,$36,$63,$41,$00,$00)
EEPROM $60,($7F,$7F,$40,$40,$40,$40,$00,$00,$7F,$7F,$06,$1C,$06,$7F,$7F,$00)
EEPROM $70,($7F,$7F,$0C,$18,$7F,$7F,$00,$00,$3E,$7F,$41,$41,$7F,$3E,$00,$00)
EEPROM $80,($7F,$7F,$09,$09,$0F,$06,$00,$00,$3E,$7F,$41,$31,$6F,$5E,$00,$00)
EEPROM $90,($7F,$7F,$09,$19,$7F,$66,$00,$00,$26,$6F,$49,$49,$7B,$32,$00,$00)
EEPROM $A0,($01,$01,$7F,$7F,$01,$01,$00,$00,$3F,$7F,$40,$40,$7F,$3F,$00,$00)
EEPROM $B0,($1F,$3F,$60,$60,$3F,$1F,$00,$00,$7F,$7F,$30,$1C,$30,$7F,$7F,$00)
EEPROM $C0,($63,$77,$1C,$1C,$77,$63,$00,$00,$07,$0F,$78,$78,$0F,$07,$00,$00)
EEPROM $D0,($61,$71,$59,$4D,$47,$43,$00,$00,$00,$00,$5F,$5F,$00,$00,$00,$00)
EEPROM $E0,($02,$03,$59,$5D,$07,$02,$00,$00,$00,$80,$E0,$60,$00,$00,$00,$00)
EEPROM $F0,($00,$00,$60,$60,$00,$00,$00,$00,$07,$07,$00,$07,$07,$00,$00,$00)

The code isn't very robust - it doesn't check the state of the LCD's busy flag as I'm assuming that a 4MHz PIC running an interpreted BASIC is too slow to manage to write another byte to the LCD driver before it has finished processing the last one.

The font was generated from the following image (it's the BBC Micro font):

2008.08.01.02.Font.png

It's rotated through 90° as, unlike the LCD driver in the TI-83+, each byte written outputs 8 pixels vertically, with the least significant at the top. (On the TI-83+, each byte written outputs 8 pixels horizontally, with the most significant bit on the left). More interestingly, this graphical LCD is made up of two 64×64 regions next to eachother, and by controlling two chip select pins you can control whether each byte written updates the left side, the right side, neither or both. I'm entirely sure how I could use this, though, other than not-very-exciting tricks like clearing the LCD extra-fast.

Finally, here's a video of the LCD test in action. It's not very speedy, but will hopefully pick up some speed once I figure out how I'm going to use that Z80180 CPU. smile.gif

Graphical text, BASIC tokeniser and flood-filling

Tuesday, 29th July 2008

I've got a fairly hackish "graphical text" mode set up (enabled with VDU 5, disabled with VDU 4) that causes all text that is sent to the console to be drawn using the current graphics mode (at the graphics cursor position, using the graphics colour and logical plotting mode and graphics viewport). This allows text to be drawn at any position on-screen, but is (understandably) a bit slower and doesn't let you do some of the things you may be used to (such as scrolling text, copy-key editing and the like).

2008.07.27.01.gif

I've also done some work on a tool to convert files from the PC to use in BBC BASIC. It takes the form of a Notepad-like text editor:

editor.2008.07.27.01.png

BBC BASIC programs are stored in a tokenised format (usually .bbc files on a PC) and need to be wrapped into a .8xp for transferring to the calculator. The editor above can open .8xp, .bbc and .txt directly, and will save to .8xp.

The detokeniser can be passed a number of settings, which can be used to (for example) generate HTML output, like this. The indentation is generated by the detokeniser (leading/trailing whitespace is stripped by the tokeniser). The tool can also be used to directly convert binaries into .8xp files if need be.

floodfill.2008.07.28.01.gif floodfill.2008.07.28.02.gif floodfill.2008.07.28.03.gif

I've been doing a little work on a flood-filling algorithm. (PLOT 128-135, 136-143). The above images show its progress; on the left is the first version (which can only fill in black). There is a hole in the bottom-left of the shape, so the leaking is intentional. It also stops one pixel away from the screen boundary -- this too is intentional (it clips against the viewport). The second version, in the middle, plugs the leak and applies a pattern (which will be a dither pattern in BBC BASIC) to the filled area. On the right is the third version, which will fill over black or white pixels with a pattern.

The main filling algorithm needs a 764 byte buffer for the node queue and three 16-bit pointer variables to manage the queue. I've rounded the queue size up to 768 bytes, so it fits neatly on one of the RAM areas designed to store a bitmap of the display.

The problem is filling with a pattern. The way I currently do this is to back up the current screen image to a second 768-byte buffer, fill in black as normal, then compare the two buffers to work out which bits have been filled and use those as a mask to overlay the dither pattern. This is quite a lot of RAM, just to flood-fill an image!

For those who are interested, I'm using the "practical" implementation of a flood fill algorithm from Wikipedia.

Text viewports and sprites

Monday, 21st July 2008

Back to work on the TI-83 Plus port of BBC BASIC! To complement the graphics viewport I've added support for text viewports — this lets you define the area the text console uses. The following VDU commands are now supported:

  • VDU 24,<left>;<top>;<right>;<bottom>;
    Define a graphics viewport.
  • VDU 28,<left>,<top>,<right>,<bottom>
    Define a text viewport.
  • VDU 26
    Reset both viewports to their default settings (full screen).
  • VDU 29,<x>;<y>;
    Defines the graphics origin.
2008.07.13.01.gif

The above screenshots defines the graphics viewport to fill the left hand side of the screen and shunts the text viewport over to the right half, using the following code:

VDU 24,0;0;47;63; 
VDU 28,12,0,23,9 
VDU 29,24;32;
I've also added simple sprite drawing to BBC BASIC's PLOT command. PLOT usually takes a shape type and two coordinates, but for sprites (shapes 208..215) I've added an extra parameter - the address of the sprite data to use.

2008.07.20.01.gif
   10 DIM ball 7 
   20 ball?0=&3C 
   30 ball?1=&5E 
   40 ball?2=&8F 
   50 ball?3=&DF 
   60 ball?4=&FF 
   70 ball?5=&FF 
   80 ball?6=&7E 
   90 ball?7=&3C 
  100 *REFRESH OFF 
  110 REPEAT 
  120   CLG 
  130   T=TIME/100 
  140   FOR P=0 TO 5 
  150     A=P/3*PI+T 
  160     X=16*SIN(A)+44 
  170     Y=16*COS(A)+28 
  180     PLOT 213,X,Y,ball 
  190   NEXT 
  200   *REFRESH 
  210 UNTIL INKEY(0)<>-1 
  220 *REFRESH ON

The above code allocates 8 bytes of memory (DIM ball 7) then copies the sprite data to it by use of the ? indirection operator. This is a little laborious, so in reality you'd probably store your sprites in a binary file external to the main program, and might load them like this:

   10 ball%=FN_loadSprite("SPRITES",0) 
   20 face%=FN_loadSprite("SPRITES",1) 
   30 *REFRESH OFF 
   40 REPEAT 
   50   CLG 
   60   T=TIME/100 
   70   FOR P=0 TO 5 
   80     A=P/3*PI+T 
   90     X=16*SIN(A)+44 
  100     Y=16*COS(A)+28 
  110     PLOT 213,X,Y,ball% 
  120   NEXT 
  130   PLOT 213,44,28,face% 
  140   *REFRESH 
  150 UNTIL INKEY(0)<>-1 
  160 *REFRESH ON 
  170 END 
  180 DEF FN_loadSprite(f$,i%) 
  190 fh%=OPENIN(f$) 
  200 PTR#fh%=i%*8 
  210 DIM spr 7 
  220 FOR j%=0 TO 7 
  230   spr?j%=BGET#fh% 
  240 NEXT j% 
  250 CLOSE#fh% 
  260 =spr 
  270 ENDPROC

(Note FN_loadSprite() at the end of the program). The result is the following:

2008.07.20.02.gif

Next up: drawing text at the graphics cursor position (as sprites).

XNA DOOM3

Thursday, 3rd July 2008

This journal is starting to look a little drab, so here's a splash of colour.

2008.07.03.01.jpg.thumb.jpg

Not really all that colourful, on second thoughts. smile.gif I fancied a short break from BBC BASIC, and seeing that the current XNA CTP supports VS 2008 I thought I'd try a bit more work on hardware-accelerated 3D. I've never worked with shadows, bump mapping or visibility portals, and have a copy of DOOM 3, so thought that would provide a nice set of resources to experiment with.

2008.07.03.02.jpg.thumb.jpg

The screenshots are generated by simply brute-force rendering of all surfaces of all models in a level (.proc) file. The odd colours and lighting are courtesy of the default lighting provided by the BasicEffect class. The level files are simple to parse (they're just text files breaking each surface down into vertex and index arrays, ready to be fed to the video hardware), so though I've not found much documentation on them it's been pretty easy to guess what's what so far.

2008.07.03.03.jpg.thumb.jpg

The above textures are loaded by taking the material name and appending .tga, which seems to return a random mixture of specular, diffuse or normal maps. There is a materials directory that appears to contain definitions for which image file to use for each different type of texture map, so that looks like the next thing to investigate.

Clipped graphics and ellipses

Monday, 23rd June 2008

qarnos — author of the superb Aether 3D engine — has been lending a hand with the BBC BASIC graphics API and contributed a large amount of very useful code.

2008.06.19.01.gif

First up is some code to clip 16-bit line coordinates down to 8-bit coordinates. This allows for lines to be partially (or completely) off the screen.

2008.06.21.02.gif   2008.06.21.01.gif

He's also written a fast ellipse drawing and filling routine. The ellipses are also clipped to the viewport and are filled with an 8×8 pixel pattern.

2008.06.23.01.gif

The graphics viewport can be redefined using the VDU 24,left;top;right;bottom; command as demonstrated in the above example.

2008.06.23.02.gif   2008.06.23.03.gif

GCOL can also be used to set a plotting mode; either plotting the specified colour directly, performing a logical operation (OR, AND, EOR) or inverting the existing colour.

2008.06.23.04.gif

All but the last of the above screenshots are the result of running BBC BASIC on a TI-83+ SE at 15MHz. The final screenshot is running at the regular 6MHz.

Page 24 of 54 120 21 22 23 24 25 26 27 2854

Older postsNewer postsLatest posts RSSSearchBrowse by dateIndexTags