summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/hp9845.cpp
blob: 685310442d8a1f2ac60a844a37e8236a04caebc6 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                         






                          








                                     
                   

                   
                                        
           
                     
                                                                         
                                      


                                                                                                         

                
                        
                     
                                  
                            
                                     
                       
 





                                             


                                       



                                                                                                              
 
                           
                                        


                                  
                                  
                                  
                                  
                                                                       

                                                                      
                                                                     
 



















                                                                          

                                      


                                         
                                                                                        

                                                 

                                                                                                     

  


                                  


                                          
                                                                                         
                                                  

                                                     
                                                           
                                                             
                                                               


                                          
                                          


                                                  



                                                                                                     

                                                      
 
                                                             
                                                       
 
                                                                 
 
                                                    

                                          


                                                                 
 
                                                  
                              




                                               
                                                 
 
                                            
 


                                                     
 
        

                                                               
                                                        
                                                  
                                                         



                                  
                                                      

                                                   
 

                                                    
                                                                                                      
                                                                   



                               





                                                  

                              


                                      
                                       



                                      

                                                 



























                                                                   
 

                                     
                                    




                                             

  
                                 
                                                                                                        





                                                                      



                                                                                                    
                                                                                                       










                                                                                                                                        




                                                                                                     













                                                                                                                                   




                                                                                               









                                                                                                                                    





                                                                                                 











                                                                                                                            





                                                                                                     








                                                                                                                                     
                                                                                                 



                                                                                                                            

                                                                                                     










                                                                                                                                    







                                                                                                  
                                                                                                     
                                                                                             





                                                                                                                            
                                                                                                  
                                                                                                  


                                                                                                             

                                                                                                                     









                                                                                                                                    

               




                                                                                                          

                                                                                                           




                                                                                                         







                                                                   
                                                         
 
                                                                      



                                   





                                                
                                                          



                                         




                                                               

                                  
                                                  



                                                                  

                                       



                                             
                                                                



                                                  















                                                                                                                                          



                                                                                                                                                                          






































                                                                                                                                   

 
                                                                                                    
 


                                                       
 
                                                                     
 
                                      



                                                                                                              
                        

                                                                     
                                                                                                                          

                                                                         






                                                                                                                           






                                                                                                          


                                                                                                                                           
                                                        
                                                                                                            








                                                                                                             
                                                                                                                                  


                                                 



                                                           

















                                                                                                        
 
 

                                                     
                                              

 

                                                               












                                                                                                     
 
 

                                                  








                                                                                                                                                                                                                                                             
 
 

                                       


































                                                                   

 
                                        
 

































                                                                               
 
 

                                                               












                                                                                                        



                                                          
















































































































































                                                                                                                                                                                                     



                                             


                                                                   
 
                                                                     
 




                                                                      
 
                             
 
                                                      
 
                                    
 


                                                          

 

                                                                 


































                                                                                                                                            

 

                                                
                                              
                                                                                             

                                                     
                                                                                             
                                                     
                 

 
                                    
 
                                                                         
                                                                         



                                                    























































                                                                                             
                                                             








                                                                                                         



                                           
                                             



                                         
                                   



                                             

                                           
                             
                                   










                                                                                                  



                                  
                                     


                                                                                



                                                                          



                                                   

 

                                           
                            
                                                                    
                        
                                                                    

                             



                                           
                                      

                                                     



                                           
                                      

                                                       

 



                                                         







                                                              
                                                            





                                                         







                                                              
                                                            

                  
                                                                          



                                                                        
                                                                                           
                                                                         
                                                                                           
                                                                         


                                                                 






                                                                                                                  


                                                                                                                           

                                                   
                                                                                                                                                



                                                     

                                                    
                                                  
                                                    
                                   
                                                 
                                                                     
                                                                      
 
                         
                                                                  
                                                               
                                                       
                                                                                                                                
                                                                  
                                                        

                                                                                                  
                                                                          
 


                                                                                                     






                                                                         




                                                                           
 



















                                                                                       
 
                                                                    


                    
                                                                    

                                                                                                                                         
                                                                    





                                                                                                                                         
                                                                    








                                                                                                                                   
                                                                    










                                                                                                                                   
                                         
                                                                                                        

                                                                                                                     

                                                                                                                                     
 

                                                                                                                                    

     
                                                                    









                                                                                                                                             
 
                                                                         







                                                                                                                                                  
 
                                                                    









                                                                                                                                             
 
                                                                         





                                                                                                                                           
 
                                                                           

                                                                                                                                              
 
                                                                           



                                                                                                                                                  
      




                               



                                                                                                                                                                                  
                                                                                                                       

                                                                                                                                                                                  
// license:BSD-3-Clause
// copyright-holders:Curt Coder, F. Ulivi
/*

    HP 9845

    http://www.hp9845.net/

*/
// **************************
// Driver for HP 9845B system
// **************************
//
// What's in:
// - Emulation of both 5061-3001 CPUs
// - LPU & PPU ROMs
// - LPU & PPU RAMs
// - Text mode screen
// - Graphic screen
// - Keyboard
// - T15 tape drive
// - Software list to load optional ROMs
// - Beeper
// What's not yet in:
// - Better naming of tape drive image (it's now "magt", should be "t15")
// - Better documentation of this file
// What's wrong:
// - I'm using character generator from HP64K (another driver of mine): no known dump of the original one
// - Speed, as usual

#include "emu.h"
#include "cpu/z80/z80.h"
#include "softlist.h"
#include "cpu/hphybrid/hphybrid.h"
#include "machine/hp_taco.h"
#include "bus/hp_optroms/hp_optrom.h"
#include "sound/beep.h"

#define BIT_MASK(n) (1U << (n))

// Macros to clear/set single bits
#define BIT_CLR(w , n)  ((w) &= ~BIT_MASK(n))
#define BIT_SET(w , n)  ((w) |= BIT_MASK(n))

// Base address of video buffer
#define VIDEO_BUFFER_BASE       0x17000

// For test "B" of alpha video to succeed this must be < 234
// Basically "B" test is designed to intentionally prevent line buffer to be filled so that display is blanked
// from 2nd row on. This in turn prevents "BAD" text to be visible on screen.
#define MAX_WORD_PER_ROW        220

// Constants of alpha video
#define VIDEO_PIXEL_CLOCK       20849400
#define VIDEO_CHAR_WIDTH        9
#define VIDEO_CHAR_HEIGHT       15
#define VIDEO_CHAR_COLUMNS      80
#define VIDEO_CHAR_TOTAL        99
#define VIDEO_CHAR_ROWS         25
#define VIDEO_ROWS_TOTAL        26
#define VIDEO_HBSTART           (VIDEO_CHAR_WIDTH * VIDEO_CHAR_COLUMNS)
#define VIDEO_HTOTAL            (VIDEO_CHAR_WIDTH * VIDEO_CHAR_TOTAL)
#define VIDEO_VTOTAL            (VIDEO_CHAR_HEIGHT * VIDEO_ROWS_TOTAL)
#define VIDEO_ACTIVE_SCANLINES  (VIDEO_CHAR_HEIGHT * VIDEO_CHAR_ROWS)

// Constants of graphic video
// Pixel clock is 20.8494 MHz (the same as alpha video)
// Horizontal counter counts in [1..727] range
// Vertical counter counts in [34..511] range
#define GVIDEO_HTOTAL           727
#define GVIDEO_HCNT_OFF         1       // Actual start value of h counter
#define GVIDEO_HBEND            (69 - GVIDEO_HCNT_OFF)
#define GVIDEO_HPIXELS          560
#define GVIDEO_HBSTART          (GVIDEO_HBEND + GVIDEO_HPIXELS)
#define GVIDEO_VTOTAL           478
#define GVIDEO_VCNT_OFF         34      // Actual start value of v counter
#define GVIDEO_VBEND            (50 - GVIDEO_VCNT_OFF)
#define GVIDEO_VPIXELS          455
#define GVIDEO_VBSTART          (GVIDEO_VBEND + GVIDEO_VPIXELS)
#define GVIDEO_MEM_SIZE         16384
#define GVIDEO_ADDR_MASK        (GVIDEO_MEM_SIZE - 1)
#define GVIDEO_PA               13

#define T15_PA                  15

#define KEY_SCAN_OSCILLATOR     327680

class hp9845_state : public driver_device
{
public:
	hp9845_state(const machine_config &mconfig, device_type type, const char *tag) :
		driver_device(mconfig, type, tag)
	{ }

	UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
};

static INPUT_PORTS_START( hp9845 )
INPUT_PORTS_END

class hp9845b_state : public driver_device
{
public:
	hp9845b_state(const machine_config &mconfig, device_type type, const char *tag) :
		driver_device(mconfig, type, tag),
				m_lpu(*this , "lpu"),
				m_ppu(*this , "ppu"),
				m_screen(*this , "screen"),
				m_palette(*this , "palette"),
				m_gv_timer(*this , "gv_timer"),
		m_io_key0(*this , "KEY0"),
		m_io_key1(*this , "KEY1"),
		m_io_key2(*this , "KEY2"),
		m_io_key3(*this , "KEY3"),
		m_t15(*this , "t15"),
		m_beeper(*this , "beeper"),
		m_beep_timer(*this , "beep_timer")
	{ }

	UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);

		virtual void machine_start() override;
		virtual void machine_reset() override;

		TIMER_DEVICE_CALLBACK_MEMBER(scanline_timer);
		TIMER_DEVICE_CALLBACK_MEMBER(gv_timer);

		void vblank_w(screen_device &screen, bool state);

		void set_graphic_mode(bool graphic);
	DECLARE_READ16_MEMBER(graphic_r);
	DECLARE_WRITE16_MEMBER(graphic_w);
		attotime time_to_gv_mem_availability(void) const;
		void advance_gv_fsm(bool ds , bool trigger);
		void update_graphic_bits(void);

		IRQ_CALLBACK_MEMBER(irq_callback);
	void update_irq(void);

	TIMER_DEVICE_CALLBACK_MEMBER(kb_scan);
	DECLARE_READ16_MEMBER(kb_scancode_r);
	DECLARE_READ16_MEMBER(kb_status_r);
	DECLARE_WRITE16_MEMBER(kb_irq_clear_w);
	TIMER_DEVICE_CALLBACK_MEMBER(beeper_off);

		DECLARE_WRITE8_MEMBER(pa_w);

		DECLARE_WRITE_LINE_MEMBER(t15_irq_w);
		DECLARE_WRITE_LINE_MEMBER(t15_flg_w);
		DECLARE_WRITE_LINE_MEMBER(t15_sts_w);

private:
		required_device<hp_5061_3001_cpu_device> m_lpu;
		required_device<hp_5061_3001_cpu_device> m_ppu;
		required_device<screen_device> m_screen;
	required_device<palette_device> m_palette;
		required_device<timer_device> m_gv_timer;
	required_ioport m_io_key0;
	required_ioport m_io_key1;
	required_ioport m_io_key2;
	required_ioport m_io_key3;
		required_device<hp_taco_device> m_t15;
	required_device<beep_device> m_beeper;
	required_device<timer_device> m_beep_timer;

		void set_video_mar(UINT16 mar);
		void video_fill_buff(bool buff_idx);
		void video_render_buff(unsigned video_scanline , unsigned line_in_row, bool buff_idx);
		void graphic_video_render(unsigned video_scanline);

	// Character generator
	const UINT8 *m_chargen;

		// Text mode video I/F
		typedef struct {
				UINT8 chars[ 80 ];
				UINT8 attrs[ 80 ];
				bool full;
		} video_buffer_t;

	bitmap_rgb32 m_bitmap;
		offs_t m_video_mar;
		UINT16 m_video_word;
		bool m_video_load_mar;
		bool m_video_first_mar;
		bool m_video_byte_idx;
		UINT8 m_video_attr;
		bool m_video_buff_idx;
		bool m_video_blanked;
		video_buffer_t m_video_buff[ 2 ];

		// Graphic video
		typedef enum {
				GV_STAT_RESET,
				GV_STAT_WAIT_DS_0 = GV_STAT_RESET,
				GV_STAT_WAIT_TRIG_0,
				GV_STAT_WAIT_MEM_0,
				GV_STAT_WAIT_DS_1,
				GV_STAT_WAIT_DS_2,
				GV_STAT_WAIT_TRIG_1,
				GV_STAT_WAIT_MEM_1,
				GV_STAT_WAIT_MEM_2
		} gv_fsm_state_t;

		bool m_graphic_sel;
		gv_fsm_state_t m_gv_fsm_state;
		bool m_gv_int_en;
		bool m_gv_dma_en;
		bool m_gv_ready;
		UINT8 m_gv_cmd; // U65 (GC)
		UINT16 m_gv_data_w;     // U29, U45, U28 & U44 (GC)
		UINT16 m_gv_data_r;     // U59 & U60 (GC)
		UINT16 m_gv_io_counter; // U1, U2, U14 & U15 (GC)
		UINT16 m_gv_cursor_w;   // U38 & U39 (GS)
		UINT16 m_gv_cursor_x;   // U31 & U23 (GS)
		UINT16 m_gv_cursor_y;   // U15 & U8 (GS)
		bool m_gv_cursor_gc;    // U8 (GS)
		bool m_gv_cursor_fs;    // U8 (GS)
		std::vector<UINT16> m_graphic_mem;

		// Interrupt handling
		UINT8 m_irl_pending;
		UINT8 m_irh_pending;

		// State of keyboard
		ioport_value m_kb_state[ 4 ];
		UINT8 m_kb_scancode;
		UINT16 m_kb_status;
};

static INPUT_PORTS_START(hp9845b)
		// Keyboard is arranged in a 8 x 16 matrix. Of the 128 possible positions, 118 are used.
	// Keys are mapped on bit b of KEYn
	// where b = (row & 1) << 4 + column, n = row >> 1
	// column = [0..15]
	// row = [0..7]
	PORT_START("KEY0")
	PORT_BIT(BIT_MASK(0)  , IP_ACTIVE_HIGH , IPT_UNUSED)    // N/U
	PORT_BIT(BIT_MASK(1)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("Print All")  // Print All
	PORT_BIT(BIT_MASK(2)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP+")        // KP +
	PORT_BIT(BIT_MASK(3)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP,")        // KP ,
	PORT_BIT(BIT_MASK(4)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP.")        // KP .
		PORT_BIT(BIT_MASK(5)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP0")        // KP 0
	PORT_BIT(BIT_MASK(6)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_F12)  PORT_NAME("Execute")    // Execute
	PORT_BIT(BIT_MASK(7)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_F11)  PORT_NAME("Cont")       // Cont
	PORT_BIT(BIT_MASK(8)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))        // Right
	PORT_BIT(BIT_MASK(9)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')  // Space
	PORT_BIT(BIT_MASK(10)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')  // /
	PORT_BIT(BIT_MASK(11)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')  // <
	PORT_BIT(BIT_MASK(12)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_N)     PORT_CHAR('n') PORT_CHAR('N')  // N
	PORT_BIT(BIT_MASK(13)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_V)     PORT_CHAR('v') PORT_CHAR('V')  // V
	PORT_BIT(BIT_MASK(14)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_X)     PORT_CHAR('x') PORT_CHAR('X')  // X
	PORT_BIT(BIT_MASK(15)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT)    PORT_CHAR(UCHAR_SHIFT_1)   // Shift
	PORT_BIT(BIT_MASK(16)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(17)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Auto start") // Auto Start
	PORT_BIT(BIT_MASK(18)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP-")        // KP -
	PORT_BIT(BIT_MASK(19)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP3")        // KP 3
	PORT_BIT(BIT_MASK(20)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP2")        // KP 2
	PORT_BIT(BIT_MASK(21)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP1")        // KP 1
	PORT_BIT(BIT_MASK(22)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(23)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))  // Left
	PORT_BIT(BIT_MASK(24)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // Repeat
	PORT_BIT(BIT_MASK(25)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))  // Down
	PORT_BIT(BIT_MASK(26)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(27)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')   // >
	PORT_BIT(BIT_MASK(28)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_M)     PORT_CHAR('m') PORT_CHAR('M')  // M
	PORT_BIT(BIT_MASK(29)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_B)     PORT_CHAR('b') PORT_CHAR('B')  // B
	PORT_BIT(BIT_MASK(30)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_C)     PORT_CHAR('c') PORT_CHAR('C')  // C
	PORT_BIT(BIT_MASK(31)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Z)     PORT_CHAR('z') PORT_CHAR('Z')  // Z

	PORT_START("KEY1")
	PORT_BIT(BIT_MASK(0)  , IP_ACTIVE_HIGH , IPT_UNUSED)    // N/U
	PORT_BIT(BIT_MASK(1)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_INSERT)       PORT_NAME("INSCHAR")    // Ins Char
	PORT_BIT(BIT_MASK(2)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP*")        // KP *
	PORT_BIT(BIT_MASK(3)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP6")        // KP 6
	PORT_BIT(BIT_MASK(4)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP5")        // KP 5
	PORT_BIT(BIT_MASK(5)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP4")        // KP 4
	PORT_BIT(BIT_MASK(6)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP=")        // KP =
	PORT_BIT(BIT_MASK(7)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_F10)  PORT_NAME("Pause")      // Pause
	PORT_BIT(BIT_MASK(8)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_UP)   PORT_CHAR(UCHAR_MAMEKEY(UP))    // Up
	PORT_BIT(BIT_MASK(9)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_ENTER)        PORT_CHAR(13)   // Store
	PORT_BIT(BIT_MASK(10)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON)     PORT_CHAR(';') PORT_CHAR(':')      // :
	PORT_BIT(BIT_MASK(11)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_K)     PORT_CHAR('k') PORT_CHAR('K')  // K
	PORT_BIT(BIT_MASK(12)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_H)     PORT_CHAR('h') PORT_CHAR('H')  // H
	PORT_BIT(BIT_MASK(13)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F)     PORT_CHAR('f') PORT_CHAR('F')  // F
	PORT_BIT(BIT_MASK(14)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_S)     PORT_CHAR('s') PORT_CHAR('S')  // S
	PORT_BIT(BIT_MASK(15)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(16)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(17)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("INSLN")      // Ins Ln
	PORT_BIT(BIT_MASK(18)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP/")        // KP /
	PORT_BIT(BIT_MASK(19)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP9")        // KP 9
	PORT_BIT(BIT_MASK(20)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP8")        // KP 8
	PORT_BIT(BIT_MASK(21)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("KP7")        // KP 7
	PORT_BIT(BIT_MASK(22)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Result")     // Result
	PORT_BIT(BIT_MASK(23)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F9)   PORT_NAME("Run")        // Run
	PORT_BIT(BIT_MASK(24)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(25)  , IP_ACTIVE_HIGH , IPT_UNUSED)   // N/U
	PORT_BIT(BIT_MASK(26)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // "
	PORT_BIT(BIT_MASK(27)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_L)     PORT_CHAR('l') PORT_CHAR('L')  // L
	PORT_BIT(BIT_MASK(28)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_J)     PORT_CHAR('j') PORT_CHAR('J')  // J
	PORT_BIT(BIT_MASK(29)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_G)     PORT_CHAR('g') PORT_CHAR('G')  // G
	PORT_BIT(BIT_MASK(30)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_D)     PORT_CHAR('d') PORT_CHAR('D')  // D
	PORT_BIT(BIT_MASK(31)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_A)     PORT_CHAR('a') PORT_CHAR('A')  // A

	PORT_START("KEY2")
	PORT_BIT(BIT_MASK(0)  , IP_ACTIVE_HIGH , IPT_UNUSED)    // N/U
	PORT_BIT(BIT_MASK(1)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("DELLN")      // Del Ln
	PORT_BIT(BIT_MASK(2)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP^")        // KP ^
	PORT_BIT(BIT_MASK(3)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP)")        // KP )
	PORT_BIT(BIT_MASK(4)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KP(")        // KP (
	PORT_BIT(BIT_MASK(5)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("KPE")        // KP E
	PORT_BIT(BIT_MASK(6)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("Clear line") // Clear Line
	PORT_BIT(BIT_MASK(7)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_F8)   PORT_NAME("Stop")       // Stop
	PORT_BIT(BIT_MASK(8)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')      // |
	PORT_BIT(BIT_MASK(9)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_CODE(KEYCODE_CLOSEBRACE)   PORT_CHAR(']') PORT_CHAR('}')   // ]
	PORT_BIT(BIT_MASK(10)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_P)     PORT_CHAR('p') PORT_CHAR('P')  // P
	PORT_BIT(BIT_MASK(11)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_I)     PORT_CHAR('i') PORT_CHAR('I')  // I
	PORT_BIT(BIT_MASK(12)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Y)     PORT_CHAR('y') PORT_CHAR('Y')  // Y
	PORT_BIT(BIT_MASK(13)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_R)     PORT_CHAR('r') PORT_CHAR('R')  // R
	PORT_BIT(BIT_MASK(14)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_W)     PORT_CHAR('w') PORT_CHAR('W')  // W
	PORT_BIT(BIT_MASK(15)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL)  PORT_CHAR(UCHAR_SHIFT_2)   // Control
	PORT_BIT(BIT_MASK(16)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Typwtr")     // Typwtr
	PORT_BIT(BIT_MASK(17)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL)  PORT_NAME("DELCHAR")    // Del Char
	PORT_BIT(BIT_MASK(18)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("ROLLDOWN")   // Roll down
	PORT_BIT(BIT_MASK(19)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("ROLLUP")     // Roll up
	PORT_BIT(BIT_MASK(20)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_NAME("HOME")       // Home
	PORT_BIT(BIT_MASK(21)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Clr to end") // Clr to end
	PORT_BIT(BIT_MASK(22)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Clear")      // Clear
	PORT_BIT(BIT_MASK(23)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE)     PORT_CHAR('`') PORT_CHAR('~')      // ~
	PORT_BIT(BIT_MASK(24)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)       // BS
	PORT_BIT(BIT_MASK(25)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS)    PORT_CHAR('=') PORT_CHAR('+')      // +
	PORT_BIT(BIT_MASK(26)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')      // [
	PORT_BIT(BIT_MASK(27)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_O)     PORT_CHAR('o') PORT_CHAR('O')  // O
	PORT_BIT(BIT_MASK(28)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_U)     PORT_CHAR('u') PORT_CHAR('U')  // U
	PORT_BIT(BIT_MASK(29)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_T)     PORT_CHAR('t') PORT_CHAR('T')  // T
	PORT_BIT(BIT_MASK(30)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_E)     PORT_CHAR('e') PORT_CHAR('E')  // E
	PORT_BIT(BIT_MASK(31)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Q)     PORT_CHAR('q') PORT_CHAR('Q')  // Q

	PORT_START("KEY3")
	PORT_BIT(BIT_MASK(0)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("Tab set")    // Tab set
	PORT_BIT(BIT_MASK(1)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("Recall")     // Recall
	PORT_BIT(BIT_MASK(2)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K15")        // K15
	PORT_BIT(BIT_MASK(3)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K14")        // K14
	PORT_BIT(BIT_MASK(4)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K13")        // K13
	PORT_BIT(BIT_MASK(5)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K12")        // K12
	PORT_BIT(BIT_MASK(6)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K11")        // K11
	PORT_BIT(BIT_MASK(7)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K10")        // K10
		PORT_BIT(BIT_MASK(8)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K9")         // K9
	PORT_BIT(BIT_MASK(9)  , IP_ACTIVE_HIGH , IPT_KEYBOARD)  PORT_NAME("K8")         // K8
	PORT_BIT(BIT_MASK(10)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_0)     PORT_CHAR('0') // 0
	PORT_BIT(BIT_MASK(11)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_8)     PORT_CHAR('8') PORT_CHAR('(')  // 8
	PORT_BIT(BIT_MASK(12)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6)     PORT_CHAR('6') PORT_CHAR('&')  // 6
	PORT_BIT(BIT_MASK(13)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_4)     PORT_CHAR('4') PORT_CHAR('$')  // 4
	PORT_BIT(BIT_MASK(14)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_2)     PORT_CHAR('2') PORT_CHAR('"')  // 2
	PORT_BIT(BIT_MASK(15)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB)   PORT_CHAR('\t')        // Tab
	PORT_BIT(BIT_MASK(16)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Tab clr")    // Tab clr
		PORT_BIT(BIT_MASK(17)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Step")  // Step
	PORT_BIT(BIT_MASK(18)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F7)   PORT_NAME("K7") // K7
	PORT_BIT(BIT_MASK(19)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F6)   PORT_NAME("K6") // K6
	PORT_BIT(BIT_MASK(20)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F5)   PORT_NAME("K5") // K5
		PORT_BIT(BIT_MASK(21)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F4)   PORT_NAME("K4") // K4
		PORT_BIT(BIT_MASK(22)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F3)   PORT_NAME("K3") // K3
	PORT_BIT(BIT_MASK(23)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F2)   PORT_NAME("K2") // K2
	PORT_BIT(BIT_MASK(24)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F1)   PORT_NAME("K1") // K1
	PORT_BIT(BIT_MASK(25)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC)  PORT_NAME("K0") // K0
	PORT_BIT(BIT_MASK(26)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS)     PORT_CHAR('-') PORT_CHAR('_')      // _
	PORT_BIT(BIT_MASK(27)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_9)     PORT_CHAR('9') PORT_CHAR(')')  // 9
	PORT_BIT(BIT_MASK(28)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_7)     PORT_CHAR('7') PORT_CHAR('\'') // 7
	PORT_BIT(BIT_MASK(29)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_5)     PORT_CHAR('5') PORT_CHAR('%')  // 5
	PORT_BIT(BIT_MASK(30)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3)     PORT_CHAR('3') PORT_CHAR('#')  // 3
	PORT_BIT(BIT_MASK(31)  , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_1)     PORT_CHAR('1') PORT_CHAR('!')  // 1

INPUT_PORTS_END

UINT32 hp9845_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	return 0;
}

UINT32 hp9845b_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
		if (m_graphic_sel) {
				copybitmap(bitmap, m_bitmap, 0, 0, GVIDEO_HBEND, GVIDEO_VBEND, cliprect);
		} else {
				copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
		}

	return 0;
}

void hp9845b_state::machine_start()
{
	machine().first_screen()->register_screen_bitmap(m_bitmap);

		m_chargen = memregion("chargen")->base();

				m_graphic_mem.resize(GVIDEO_MEM_SIZE);
}

void hp9845b_state::machine_reset()
{
		m_lpu->halt_w(1);
		m_ppu->halt_w(0);

		// Some sensible defaults
		m_video_mar = VIDEO_BUFFER_BASE;
		m_video_load_mar = false;
				m_video_first_mar = false;
		m_video_byte_idx = false;
		m_video_attr = 0;
		m_video_buff_idx = false;
		m_video_blanked = false;
				m_graphic_sel = false;
				m_gv_fsm_state = GV_STAT_RESET;
				m_gv_int_en = false;
				m_gv_dma_en = false;
				m_gv_ready = true;

		m_irl_pending = 0;
				m_irh_pending = 0;

		memset(&m_kb_state[ 0 ] , 0 , sizeof(m_kb_state));
		m_kb_scancode = 0x7f;
		m_kb_status = 0;

		m_beeper->set_state(0);
}

void hp9845b_state::set_video_mar(UINT16 mar)
{
		m_video_mar = (mar & 0xfff) | VIDEO_BUFFER_BASE;
}

void hp9845b_state::video_fill_buff(bool buff_idx)
{
		unsigned char_idx = 0;
		unsigned iters = 0;
		UINT8 byte;
		address_space& prog_space = m_ppu->space(AS_PROGRAM);

		m_video_buff[ buff_idx ].full = false;

		while (1) {
				if (!m_video_byte_idx) {
						if (iters++ >= MAX_WORD_PER_ROW) {
								// Limit on accesses per row reached
								break;
						}
						m_video_word = prog_space.read_word(m_video_mar << 1);
						if (m_video_load_mar) {
								// Load new address into MAR after start of a new frame or NWA instruction
														if (m_video_first_mar) {
																set_graphic_mode(!BIT(m_video_word , 15));
																m_video_first_mar = false;
														}
								set_video_mar(~m_video_word);
								m_video_load_mar = false;
								continue;
						} else {
								// Read normal word from frame buffer, start parsing at MSB
								set_video_mar(m_video_mar + 1);
								byte = (UINT8)(m_video_word >> 8);
								m_video_byte_idx = true;
						}
				} else {
						// Parse LSB
						byte = (UINT8)(m_video_word & 0xff);
						m_video_byte_idx = false;
				}
				if ((byte & 0xc0) == 0x80) {
						// Attribute command
						m_video_attr = byte & 0x1f;
				} else if ((byte & 0xc1) == 0xc0) {
						// New Word Address (NWA)
						m_video_load_mar = true;
						m_video_byte_idx = false;
				} else if ((byte & 0xc1) == 0xc1) {
						// End of line (EOL)
						// Fill rest of buffer with spaces
						memset(&m_video_buff[ buff_idx ].chars[ char_idx ] , 0x20 , 80 - char_idx);
						memset(&m_video_buff[ buff_idx ].attrs[ char_idx ] , m_video_attr , 80 - char_idx);
						m_video_buff[ buff_idx ].full = true;
						break;
				} else {
						// Normal character
						m_video_buff[ buff_idx ].chars[ char_idx ] = byte;
						m_video_buff[ buff_idx ].attrs[ char_idx ] = m_video_attr;
						char_idx++;
						if (char_idx == 80) {
								m_video_buff[ buff_idx ].full = true;
								break;
						}
				}
		}
}

void hp9845b_state::video_render_buff(unsigned video_scanline , unsigned line_in_row, bool buff_idx)
{
		if (!m_video_buff[ buff_idx ].full) {
				m_video_blanked = true;
		}

				const pen_t *pen = m_palette->pens();

		if (m_video_blanked) {
						// Blank scanline
						for (unsigned i = 0; i < VIDEO_HBSTART; i++) {
								m_bitmap.pix32(video_scanline , i) = pen[ 0 ];
						}
		} else {
				bool cursor_line = line_in_row == 12;
				bool ul_line = line_in_row == 14;
								unsigned video_frame = (unsigned)m_screen->frame_number();
				bool cursor_blink = BIT(video_frame , 3);
				bool char_blink = BIT(video_frame , 4);

				for (unsigned i = 0; i < 80; i++) {
						UINT8 charcode = m_video_buff[ buff_idx ].chars[ i ];
						UINT8 attrs = m_video_buff[ buff_idx ].attrs[ i ];
						UINT8 chargen_byte = m_chargen[ line_in_row  | ((unsigned)charcode << 4) ];
						UINT16 pixels;

						// TODO: Check if order of bits in "pixels" is ok

						if ((ul_line && BIT(attrs , 3)) ||
							(cursor_line && cursor_blink && BIT(attrs , 0))) {
								pixels = ~0;
						} else if (char_blink && BIT(attrs , 2)) {
								pixels = 0;
						} else if (BIT(attrs , 4)) {
								// Optional character generator ROM not installed, it reads as 1 everywhere
								pixels = 0x7f << 1;
						} else {
								pixels = (UINT16)(chargen_byte & 0x7f) << 1;
						}

						if (BIT(attrs , 1)) {
								pixels = ~pixels;
						}

						for (unsigned j = 0; j < 9; j++) {
								bool pixel = (pixels & (1U << (8 - j))) != 0;

								m_bitmap.pix32(video_scanline , i * 9 + j) = pen[ pixel ? 1 : 0 ];
						}
				}
		}
}

TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::scanline_timer)
{
		unsigned video_scanline = param;

		if (m_graphic_sel) {
				if (video_scanline >= GVIDEO_VBEND && video_scanline < GVIDEO_VBSTART) {
						graphic_video_render(video_scanline);
				}
		} else if (video_scanline < VIDEO_ACTIVE_SCANLINES) {
				unsigned row = video_scanline / VIDEO_CHAR_HEIGHT;
				unsigned line_in_row = video_scanline - row * VIDEO_CHAR_HEIGHT;

				if (line_in_row == 0) {
						// Start of new row, swap buffers
						m_video_buff_idx = !m_video_buff_idx;
						video_fill_buff(!m_video_buff_idx);
				}

				video_render_buff(video_scanline , line_in_row , m_video_buff_idx);
		}
}

TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::gv_timer)
{
		advance_gv_fsm(false , false);
}

void hp9845b_state::vblank_w(screen_device &screen, bool state)
{
				// VBlank signal is fed into HALT flag of PPU
				m_ppu->halt_w(state);

				if (state) {
								// Start of V blank
								set_video_mar(0);
								m_video_load_mar = true;
								m_video_first_mar = true;
								m_video_byte_idx = false;
								m_video_blanked = false;
								m_video_buff_idx = !m_video_buff_idx;
								video_fill_buff(!m_video_buff_idx);
				}
}

void hp9845b_state::set_graphic_mode(bool graphic)
{
		if (graphic != m_graphic_sel) {
				m_graphic_sel = graphic;
				logerror("GS=%d\n" , graphic);
				if (m_graphic_sel) {
						m_screen->configure(GVIDEO_HTOTAL , GVIDEO_VTOTAL , rectangle(GVIDEO_HBEND , GVIDEO_HBSTART - 1 , GVIDEO_VBEND , GVIDEO_VBSTART - 1) , HZ_TO_ATTOSECONDS(VIDEO_PIXEL_CLOCK) * GVIDEO_HTOTAL * GVIDEO_VTOTAL);
				} else {
						m_screen->configure(VIDEO_HTOTAL , VIDEO_VTOTAL , rectangle(0 , VIDEO_HBSTART - 1 , 0 , VIDEO_ACTIVE_SCANLINES - 1) , HZ_TO_ATTOSECONDS(VIDEO_PIXEL_CLOCK) * VIDEO_HTOTAL * VIDEO_VTOTAL);
				}
		}
}

READ16_MEMBER(hp9845b_state::graphic_r)
{
		UINT16 res = 0;

		switch (offset) {
		case 0:
				// R4: data register
				res = m_gv_data_r;
				advance_gv_fsm(true , false);
				break;

		case 1:
				// R5: status register
				if (m_gv_int_en) {
						BIT_SET(res, 7);
				}
				if (m_gv_dma_en) {
						BIT_SET(res, 6);
				}
				BIT_SET(res, 5);
				break;

		case 2:
				// R6: data register with DMA TC
				m_gv_dma_en = false;
				res = m_gv_data_r;
				advance_gv_fsm(true , false);
				break;

		case 3:
				// R7: not mapped
				break;
		}

		//logerror("rd gv R%u = %04x\n", 4 + offset , res);

		return res;
}

WRITE16_MEMBER(hp9845b_state::graphic_w)
{
		//logerror("wr gv R%u = %04x\n", 4 + offset , data);

		switch (offset) {
		case 0:
				// R4: data register
				m_gv_data_w = data;
				m_gv_cursor_w = data;
				advance_gv_fsm(true , false);
				break;

		case 1:
				// R5: command register
				m_gv_cmd = (UINT8)(data & 0xf);
				if (BIT(data , 5)) {
						m_gv_fsm_state = GV_STAT_RESET;
				}
				m_gv_dma_en = BIT(data , 6) != 0;
				m_gv_int_en = BIT(data , 7) != 0;
				advance_gv_fsm(false , false);
				break;

		case 2:
				// R6: data register with DMA TC
				m_gv_dma_en = false;
				m_gv_data_w = data;
				m_gv_cursor_w = data;
				advance_gv_fsm(true , false);
				break;

		case 3:
				// R7: trigger
				advance_gv_fsm(false , true);
				break;
		}
}

attotime hp9845b_state::time_to_gv_mem_availability(void) const
{
		if (m_graphic_sel) {
				int hpos = m_screen->hpos();
				if (hpos < (34 - GVIDEO_HCNT_OFF) || hpos >= (628 - GVIDEO_HCNT_OFF)) {
						// Access to graphic memory available now
						return attotime::zero;
				} else {
						// Wait until start of hblank
						return m_screen->time_until_pos(m_screen->vpos() , 628);
				}
		} else {
				// TODO:
				return attotime::zero;
		}
}

void hp9845b_state::advance_gv_fsm(bool ds , bool trigger)
{
		bool get_out = false;

		attotime time_mem_av;

		do {
				bool act_trig = trigger || m_gv_dma_en || !BIT(m_gv_cmd , 2);

				switch (m_gv_fsm_state) {
				case GV_STAT_WAIT_DS_0:
						if ((m_gv_cmd & 0xc) == 0xc) {
								// Read command (11xx)
								m_gv_fsm_state = GV_STAT_WAIT_MEM_0;
						} else if (ds) {
								// Wait for data strobe (r/w on r4 or r6)
								m_gv_fsm_state = GV_STAT_WAIT_TRIG_0;
						} else {
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_TRIG_0:
						// Wait for trigger
						if (act_trig) {
								if (BIT(m_gv_cmd , 3)) {
										// Not a cursor command
										// Load memory address
										m_gv_io_counter = ~m_gv_data_w & GVIDEO_ADDR_MASK;
										// Write commands (10xx)
										m_gv_fsm_state = GV_STAT_WAIT_DS_2;
								} else {
										// Cursor command (0xxx)
										if (BIT(m_gv_cmd , 2)) {
												// Write X cursor position (01xx)
												m_gv_cursor_x = (~m_gv_cursor_w >> 6) & 0x3ff;
												//logerror("gv x curs pos = %u\n" , m_gv_cursor_x);
										} else {
												// Write Y cursor position and type (00xx)
												m_gv_cursor_y = (~m_gv_cursor_w >> 6) & 0x1ff;
												m_gv_cursor_gc = BIT(m_gv_cmd , 1) == 0;
												m_gv_cursor_fs = BIT(m_gv_cmd , 0) != 0;
												//logerror("gv y curs pos = %u gc = %d fs = %d\n" , m_gv_cursor_y , m_gv_cursor_gc , m_gv_cursor_fs);
										}
										m_gv_fsm_state = GV_STAT_WAIT_DS_0;
								}
						} else {
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_MEM_0:
						time_mem_av = time_to_gv_mem_availability();
						if (time_mem_av.is_zero()) {
								// Read a word from graphic memory
								m_gv_data_r = m_graphic_mem[ m_gv_io_counter ];
								//logerror("rd gv mem @%04x = %04x\n" , m_gv_io_counter , m_gv_data_r);
								m_gv_io_counter = (m_gv_io_counter + 1) & GVIDEO_ADDR_MASK;
								m_gv_fsm_state = GV_STAT_WAIT_DS_1;
						} else {
								m_gv_timer->adjust(time_mem_av);
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_DS_1:
						if (ds) {
								m_gv_fsm_state = GV_STAT_WAIT_MEM_0;
						} else {
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_DS_2:
						// Wait for data word to be written
						if (ds) {
								m_gv_fsm_state = GV_STAT_WAIT_TRIG_1;
						} else {
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_TRIG_1:
						// Wait for trigger
						if (act_trig) {
								if (BIT(m_gv_cmd , 1)) {
										// Clear words (101x)
										m_gv_data_w = 0;
										m_gv_fsm_state = GV_STAT_WAIT_MEM_1;
								} else if (BIT(m_gv_cmd , 0)) {
										// Write a single pixel (1001)
										m_gv_fsm_state = GV_STAT_WAIT_MEM_2;
								} else {
										// Write words (1000)
										m_gv_fsm_state = GV_STAT_WAIT_MEM_1;
								}
						} else {
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_MEM_1:
						time_mem_av = time_to_gv_mem_availability();
						if (time_mem_av.is_zero()) {
								// Write a full word to graphic memory
								//logerror("wr gv mem @%04x = %04x\n" , m_gv_io_counter , m_gv_data_w);
								m_graphic_mem[ m_gv_io_counter ] = m_gv_data_w;
								m_gv_io_counter = (m_gv_io_counter + 1) & GVIDEO_ADDR_MASK;
								m_gv_fsm_state = GV_STAT_WAIT_DS_2;
						} else {
								m_gv_timer->adjust(time_mem_av);
								get_out = true;
						}
						break;

				case GV_STAT_WAIT_MEM_2:
						time_mem_av = time_to_gv_mem_availability();
						if (time_mem_av.is_zero()) {
								// Write a single pixel to graphic memory
								//logerror("wr gv pixel @%04x:%x = %d\n" , m_gv_io_counter , m_gv_data_w & 0xf , BIT(m_gv_data_w , 15));
								UINT16 mask = 0x8000 >> (m_gv_data_w & 0xf);
								if (BIT(m_gv_data_w , 15)) {
										// Set pixel
										m_graphic_mem[ m_gv_io_counter ] |= mask;
								} else {
										// Clear pixel
										m_graphic_mem[ m_gv_io_counter ] &= ~mask;
								}
								// Not really needed
								m_gv_io_counter = (m_gv_io_counter + 1) & GVIDEO_ADDR_MASK;
								m_gv_fsm_state = GV_STAT_WAIT_DS_0;
						} else {
								m_gv_timer->adjust(time_mem_av);
								get_out = true;
						}
						break;

				default:
						logerror("Invalid state reached %d\n" , m_gv_fsm_state);
						m_gv_fsm_state = GV_STAT_RESET;
				}

				ds = false;
				trigger = false;
		} while (!get_out);

		update_graphic_bits();
}

void hp9845b_state::update_graphic_bits(void)
{
		m_gv_ready = m_gv_fsm_state == GV_STAT_WAIT_DS_0 ||
			m_gv_fsm_state == GV_STAT_WAIT_DS_1 ||
			m_gv_fsm_state == GV_STAT_WAIT_DS_2;

		bool irq = m_gv_int_en && !m_gv_dma_en && m_gv_ready;

		if (irq) {
				BIT_SET(m_irh_pending, GVIDEO_PA - 8);
		} else {
				BIT_CLR(m_irh_pending, GVIDEO_PA - 8);
		}

		update_irq();

		bool dmar = m_gv_ready && m_gv_dma_en;

		m_ppu->dmar_w(dmar);

		if (m_ppu->pa_r() == GVIDEO_PA) {
				m_ppu->flag_w(m_gv_ready);
		}
}

void hp9845b_state::graphic_video_render(unsigned video_scanline)
{
		const pen_t *pen = m_palette->pens();
		bool yc = (video_scanline + GVIDEO_VCNT_OFF) == (m_gv_cursor_y + 6);
		bool yw;
		bool blink;

		if (m_gv_cursor_fs) {
				yw = true;
				// Steady cursor
				blink = true;
		} else {
				yw = (video_scanline + GVIDEO_VCNT_OFF) >= (m_gv_cursor_y + 2) &&
						(video_scanline + GVIDEO_VCNT_OFF) <= (m_gv_cursor_y + 10);
				// Blinking cursor (frame freq. / 16)
				blink = BIT(m_screen->frame_number() , 3) != 0;
		}

		unsigned mem_idx = 36 * (video_scanline - GVIDEO_VBEND);
		for (unsigned i = 0; i < GVIDEO_HPIXELS; i += 16) {
				UINT16 word = m_graphic_mem[ mem_idx++ ];
				unsigned x = i;
				for (UINT16 mask = 0x8000; mask != 0; mask >>= 1) {
						unsigned cnt_h = x + GVIDEO_HBEND + GVIDEO_HCNT_OFF;
						bool xc = cnt_h == (m_gv_cursor_x + 6);
						bool xw = m_gv_cursor_fs || (cnt_h >= (m_gv_cursor_x + 2) && cnt_h <= (m_gv_cursor_x + 10));
						unsigned pixel;
						if (blink && ((xw && yc) || (yw && xc && m_gv_cursor_gc))) {
								// Cursor
								pixel = 2;
						} else {
								// Normal pixel
								pixel = (word & mask) != 0;
						}
						m_bitmap.pix32(video_scanline - GVIDEO_VBEND , x++) = pen[ pixel ];
				}
		}
}

IRQ_CALLBACK_MEMBER(hp9845b_state::irq_callback)
{
		if (irqline == HPHYBRID_IRL) {
						logerror("irq ack L %02x\n" , m_irl_pending);
				return m_irl_pending;
		} else {
						logerror("irq ack H %02x\n" , m_irh_pending);
				return m_irh_pending;
		}
}

void hp9845b_state::update_irq(void)
{
		m_ppu->set_input_line(HPHYBRID_IRL , m_irl_pending != 0);
		m_ppu->set_input_line(HPHYBRID_IRH , m_irh_pending != 0);
}

TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::kb_scan)
{
		ioport_value input[ 4 ];
		input[ 0 ] = m_io_key0->read();
		input[ 1 ] = m_io_key1->read();
		input[ 2 ] = m_io_key2->read();
		input[ 3 ] = m_io_key3->read();

		// Set status bits for "shift", "control", "auto start" & "print all" keys
		// ** Print all **
		// (R,C) = (0,1)
		// Bit 12 in kb status
		if (BIT(input[ 0 ] , 1)) {
				BIT_SET(m_kb_status , 12);
				BIT_CLR(input[ 0 ] , 1);
		} else {
				BIT_CLR(m_kb_status, 12);
		}
		// ** Auto start **
		// (R,C) = (1,1)
		// Bit 13 in kb status
		if (BIT(input[ 0 ] , 17)) {
				BIT_SET(m_kb_status , 13);
				BIT_CLR(input[ 0 ] , 17);
		} else {
				BIT_CLR(m_kb_status, 13);
		}
		// ** Control **
		// (R,C) = (4,15)
		// Bit 14 in kb status
		if (BIT(input[ 2 ] , 15)) {
				BIT_SET(m_kb_status , 14);
				BIT_CLR(input[ 2 ] , 15);
		} else {
				BIT_CLR(m_kb_status, 14);
		}
		// ** Shift **
		// (R,C) = (0,15)
		// Bit 15 in kb status
		if (BIT(input[ 0 ] , 15)) {
				BIT_SET(m_kb_status , 15);
				BIT_CLR(input[ 0 ] , 15);
		} else {
				BIT_CLR(m_kb_status, 15);
		}

		// TODO: handle repeat key
		// TODO: handle ctrl+stop

		for (unsigned i = 0; i < 128; i++) {
				ioport_value mask = BIT_MASK(i & 0x1f);
				unsigned idx = i >> 5;

				if ((input[ idx ] & ~m_kb_state[ idx ]) & mask) {
						// Key pressed, store scancode & generate IRL
						m_kb_scancode = i;
						BIT_SET(m_irl_pending , 0);
						BIT_SET(m_kb_status, 0);
						update_irq();

						// Special case: pressing stop key sets LPU "status" flag
						if (i == 0x47) {
								m_lpu->status_w(1);
						}
				}
		}

		memcpy(&m_kb_state[ 0 ] , &input[ 0 ] , sizeof(m_kb_state));
}

READ16_MEMBER(hp9845b_state::kb_scancode_r)
{
		return ~m_kb_scancode & 0x7f;
}

READ16_MEMBER(hp9845b_state::kb_status_r)
{
		return m_kb_status;
}

WRITE16_MEMBER(hp9845b_state::kb_irq_clear_w)
{
		BIT_CLR(m_irl_pending , 0);
		BIT_CLR(m_kb_status, 0);
		update_irq();
		m_lpu->status_w(0);

		if (BIT(data , 15)) {
			// Start beeper
			m_beep_timer->adjust(attotime::from_ticks(64, KEY_SCAN_OSCILLATOR / 512));
			m_beeper->set_state(1);
		}
}

TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::beeper_off)
{
	m_beeper->set_state(0);
}

WRITE8_MEMBER(hp9845b_state::pa_w)
{
		if (data == T15_PA) {
						// RHS tape drive (T15)
						m_ppu->status_w(m_t15->sts_r());
						m_ppu->flag_w(m_t15->flg_r());
				} else if (data == GVIDEO_PA) {
						// Graphic video
						m_ppu->status_w(1);
						m_ppu->flag_w(m_gv_ready);
		} else {
				m_ppu->status_w(0);
				m_ppu->flag_w(0);
		}
}

WRITE_LINE_MEMBER(hp9845b_state::t15_irq_w)
{
		if (state) {
				BIT_SET(m_irh_pending , T15_PA - 8);
		} else {
				BIT_CLR(m_irh_pending , T15_PA - 8);
		}
		update_irq();
}

WRITE_LINE_MEMBER(hp9845b_state::t15_flg_w)
{
	if (m_ppu->pa_r() == T15_PA) {
				m_ppu->flag_w(state);
		}
}

WRITE_LINE_MEMBER(hp9845b_state::t15_sts_w)
{
	if (m_ppu->pa_r() == T15_PA) {
				m_ppu->status_w(state);
		}
}

static MACHINE_CONFIG_START( hp9845a, hp9845_state )
	//MCFG_CPU_ADD("lpu", HP_5061_3010, XTAL_11_4MHz)
	//MCFG_CPU_ADD("ppu", HP_5061_3011, XTAL_11_4MHz)

	// video hardware
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_UPDATE_DRIVER(hp9845_state, screen_update)
	MCFG_SCREEN_REFRESH_RATE(60)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
	MCFG_SCREEN_SIZE(560, 455)
	MCFG_SCREEN_VISIBLE_AREA(0, 560-1, 0, 455-1)

	MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9845a_rom")
MACHINE_CONFIG_END

static MACHINE_CONFIG_START( hp9835a, hp9845_state )
	//MCFG_CPU_ADD("lpu", HP_5061_3001, XTAL_11_4MHz)
	//MCFG_CPU_ADD("ppu", HP_5061_3001, XTAL_11_4MHz)

	// video hardware
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_UPDATE_DRIVER(hp9845_state, screen_update)
	MCFG_SCREEN_REFRESH_RATE(60)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
	MCFG_SCREEN_SIZE(560, 455)
	MCFG_SCREEN_VISIBLE_AREA(0, 560-1, 0, 455-1)

	MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9835a_rom")
MACHINE_CONFIG_END

static ADDRESS_MAP_START(global_mem_map , AS_PROGRAM , 16 , hp9845b_state)
		ADDRESS_MAP_GLOBAL_MASK(0x3f7fff)
		ADDRESS_MAP_UNMAP_LOW
		AM_RANGE(0x000000 , 0x007fff) AM_RAM AM_SHARE("lpu_ram")
		AM_RANGE(0x014000 , 0x017fff) AM_RAM AM_SHARE("ppu_ram")
				AM_RANGE(0x020000 , 0x027fff) AM_RAM AM_SHARE("lpu_02_ram")
		AM_RANGE(0x030000 , 0x037fff) AM_ROM AM_REGION("lpu" , 0)
				AM_RANGE(0x040000 , 0x047fff) AM_RAM AM_SHARE("lpu_04_ram")
		AM_RANGE(0x050000 , 0x057fff) AM_ROM AM_REGION("ppu" , 0)
ADDRESS_MAP_END

static ADDRESS_MAP_START(ppu_io_map , AS_IO , 16 , hp9845b_state)
		ADDRESS_MAP_UNMAP_LOW
		// PA = 0, IC = 2
		// Keyboard scancode input
		AM_RANGE(HP_MAKE_IOADDR(0 , 2) , HP_MAKE_IOADDR(0 , 2)) AM_READ(kb_scancode_r)
		// PA = 0, IC = 3
		// Keyboard status input & keyboard interrupt clear
		AM_RANGE(HP_MAKE_IOADDR(0 , 3) , HP_MAKE_IOADDR(0 , 3)) AM_READWRITE(kb_status_r , kb_irq_clear_w)
		// PA = 13, IC = 0..3
		// Graphic video
		AM_RANGE(HP_MAKE_IOADDR(GVIDEO_PA , 0) , HP_MAKE_IOADDR(GVIDEO_PA , 3)) AM_READWRITE(graphic_r , graphic_w)
		// PA = 15, IC = 0..3
		// Right-hand side tape drive (T15)
		AM_RANGE(HP_MAKE_IOADDR(T15_PA , 0) , HP_MAKE_IOADDR(T15_PA , 3))        AM_DEVREADWRITE("t15" , hp_taco_device , reg_r , reg_w)
ADDRESS_MAP_END

static MACHINE_CONFIG_START( hp9845b, hp9845b_state )
	MCFG_CPU_ADD("lpu", HP_5061_3001, 5700000)
		MCFG_CPU_PROGRAM_MAP(global_mem_map)
		MCFG_HPHYBRID_SET_9845_BOOT(true)
	MCFG_CPU_ADD("ppu", HP_5061_3001, 5700000)
		MCFG_CPU_PROGRAM_MAP(global_mem_map)
	MCFG_CPU_IO_MAP(ppu_io_map)
		MCFG_HPHYBRID_SET_9845_BOOT(true)
	MCFG_CPU_IRQ_ACKNOWLEDGE_DRIVER(hp9845b_state , irq_callback)
		MCFG_HPHYBRID_PA_CHANGED(WRITE8(hp9845b_state , pa_w))

	// video hardware
	MCFG_SCREEN_ADD_MONOCHROME("screen", RASTER, rgb_t::green)
	MCFG_SCREEN_UPDATE_DRIVER(hp9845b_state, screen_update)
		// These parameters are for alpha video
	MCFG_SCREEN_RAW_PARAMS(VIDEO_PIXEL_CLOCK , VIDEO_HTOTAL , 0 , VIDEO_HBSTART , VIDEO_VTOTAL , 0 , VIDEO_ACTIVE_SCANLINES)
		MCFG_SCREEN_VBLANK_DRIVER(hp9845b_state, vblank_w)
	MCFG_PALETTE_ADD_MONOCHROME_HIGHLIGHT("palette")

	MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", hp9845b_state, scanline_timer, "screen", 0, 1)
		MCFG_TIMER_DRIVER_ADD("gv_timer", hp9845b_state, gv_timer)

	// Actual keyboard refresh rate should be KEY_SCAN_OSCILLATOR / 128 (2560 Hz)
	MCFG_TIMER_DRIVER_ADD_PERIODIC("kb_timer" , hp9845b_state , kb_scan , attotime::from_hz(100))

	// Beeper
	MCFG_SPEAKER_STANDARD_MONO("mono")
	MCFG_SOUND_ADD("beeper" , BEEP , KEY_SCAN_OSCILLATOR / 512)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS , "mono" , 1.00)

	MCFG_TIMER_DRIVER_ADD("beep_timer" , hp9845b_state , beeper_off);

		// Tape controller
		MCFG_DEVICE_ADD("t15" , HP_TACO , 4000000)
		MCFG_TACO_IRQ_HANDLER(WRITELINE(hp9845b_state , t15_irq_w))
		MCFG_TACO_FLG_HANDLER(WRITELINE(hp9845b_state , t15_flg_w))
		MCFG_TACO_STS_HANDLER(WRITELINE(hp9845b_state , t15_sts_w))

	// In real machine there were 8 slots for LPU ROMs and 8 slots for PPU ROMs in
	// right-hand side and left-hand side drawers, respectively.
	// Here we do away with the distinction between LPU & PPU ROMs: in the end they
	// are visible to both CPUs at the same addresses.
	MCFG_DEVICE_ADD("drawer1", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer2", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer3", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer4", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer5", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer6", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer7", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
	MCFG_DEVICE_ADD("drawer8", HP_OPTROM_SLOT, 0)
	MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)

		MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9845b_rom")
MACHINE_CONFIG_END

ROM_START( hp9845a )
	ROM_REGION( 0200000, "lpu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "09845-65544-65547-03-system_lpu.bin", 0000000, 0200000, CRC(47beb87f) SHA1(456caefacafcf19435e1e7e68b1c1e4010841664) )

	ROM_REGION( 0200000, "ppu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "09845-65540-65543-01-system_ppu.bin", 0000000, 0160000, CRC(bc0a34cc) SHA1(9ff215f4ba32ad85f144845d15f762a71e35588b) )
ROM_END

#define rom_hp9845s rom_hp9845a

ROM_START( hp9835a )
	ROM_REGION( 0200000, "lpu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-2800-03_00-system-lpu.bin", 0000000, 020000, CRC(e0b0977a) SHA1(5afdc6c725abff70b674e46688d8ab38ccf8f3c1) )
	ROM_LOAD( "1818-2801-03_10-system-lpu.bin", 0020000, 020000, CRC(c51c1e3a) SHA1(798964fa2e7a1fc149ce4400b694630049293119) )
	ROM_LOAD( "1818-2802-03_20-system-lpu.bin", 0040000, 020000, CRC(bba70a7e) SHA1(2d488594493f8dfcd753e462414cc51c24596a2c) )
	ROM_LOAD( "1818-2803-03_30-system-lpu.bin", 0060000, 020000, CRC(65e9eba6) SHA1(a11f5d37e8ed14a428335c43e785d635b02d1129) )
	ROM_LOAD( "1818-2804-03_40-system-lpu.bin", 0100000, 020000, CRC(ef83b695) SHA1(8ca2914609ece2c9c59ebba6ece3fcbc8929aeaf) )
	ROM_LOAD( "1818-2805-03_50-system-lpu.bin", 0120000, 020000, CRC(401d539f) SHA1(00bda59f71632c4d4fc3268c04262bb81ef0eeba) )
	ROM_LOAD( "1818-2806-03_60-system-lpu.bin", 0140000, 020000, CRC(fe353db5) SHA1(0fb52d82d3743008cdebebb20c488e34ce2fca4b) )
	ROM_LOAD( "1818-2807-03_70-system-lpu.bin", 0160000, 020000, CRC(45a3cc5e) SHA1(35c9959331acf7c98ab6a880915b03e3e783a656) )

	ROM_REGION( 0200000, "ppu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-2808-05_00-system-ppu.bin", 0000000, 020000, CRC(d0c96276) SHA1(cc578d586c4eda81469f29eb7cab7f667e0d5977) )
	ROM_LOAD( "1818-2809-05_30-system-ppu.bin", 0060000, 020000, CRC(ccdb7171) SHA1(1d24596bc1219983e7cb81f6987af094f2ca7d81) )
	ROM_LOAD( "1818-2810-05_40-system-ppu.bin", 0100000, 020000, CRC(97487d24) SHA1(823cd16671de8e6ff2c245060c99778acb6ff79c) )
	ROM_LOAD( "1818-2811-05_50-system-ppu.bin", 0120000, 020000, CRC(18aee6fd) SHA1(388d3b2a063ea2cfdfe9fb9f864fa5f08af817b0) )
	ROM_LOAD( "1818-2812-05_60-system-ppu.bin", 0140000, 020000, CRC(c0beeeae) SHA1(a5db36a7f7bad84c1013bd3ec4813c355f72427d) )
	ROM_LOAD( "1818-2813-05_70-system-ppu.bin", 0160000, 020000, CRC(75361bbf) SHA1(40f499c597da5c8c9a55a2a891976d946a54926b) )
ROM_END

#define rom_hp9835b rom_hp9835a

ROM_START( hp9845b )
	ROM_REGION(0x800 , "chargen" , 0)
		// Don't have the real character generator from HP9845, use the one from HP64000 for now
	ROM_LOAD("1818_2668.bin" , 0 , 0x800 , BAD_DUMP CRC(32a52664) SHA1(8b2a49a32510103ff424e8481d5ed9887f609f2f))

		ROM_REGION(0x10000, "lpu", ROMREGION_16BIT | ROMREGION_BE)
		ROM_LOAD("9845-LPU-Standard-Processor.bin", 0, 0x10000, CRC(dc266c1b) SHA1(1cf3267f13872fbbfc035b70f8b4ec6b5923f182))

		ROM_REGION(0x10000, "ppu", ROMREGION_16BIT | ROMREGION_BE)
		ROM_LOAD("9845-PPU-Standard-Graphics.bin", 0, 0x10000, CRC(f866510f) SHA1(3e22cd2072e3a5f3603a1eb8477b6b4a198d184d))

#if 0
	ROM_REGION( 0200000, "lpu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-0823-0827-03_00-revb-system_lpu.bin", 0000000, 020000, CRC(7e49c781) SHA1(866c9ebd98d94bb6f99692e29d2d83f55b38c4b6) )
	ROM_LOAD( "1818-0823-0827-03_10-revb-system_lpu.bin", 0020000, 020000, CRC(2f819e3d) SHA1(250886378c3ce2253229997007c7bf0be80a8d1d) )
	ROM_LOAD( "1818-0824-0828-03_20-reva-system_lpu.bin", 0040000, 020000, CRC(834f7063) SHA1(5c390ed74671e4663cc80d899d07b69fd1fb4be6) )
	ROM_LOAD( "1818-0824-0828-03_20-revb-system_lpu.bin", 0040000, 020000, CRC(aa221deb) SHA1(7878643405ee45405dc5269c3b6dc9459f39437b) )
	ROM_LOAD( "1818-0824-0828-03_30-reva-system_lpu.bin", 0060000, 020000, CRC(0ebafdb2) SHA1(80733bfb7026d39a294841221d80ec40eafffe34) )
	ROM_LOAD( "1818-0824-0828-03_30-revb-system_lpu.bin", 0060000, 020000, CRC(0ebafdb2) SHA1(80733bfb7026d39a294841221d80ec40eafffe34) )
	ROM_LOAD( "1818-0825-0829-03_40-revb-system_lpu.bin", 0100000, 020000, CRC(beb09a57) SHA1(b832b995fa21c219673f0c7cf215dee70698f4f1) )
	ROM_LOAD( "1818-0825-0829-03_50-revb-system_lpu.bin", 0120000, 020000, CRC(bbb06222) SHA1(b0bfe1b48fac61eb955e27e0ddfbea020e09e0eb) )
	ROM_LOAD( "1818-0826-0830-03_60-revc-system_lpu.bin", 0140000, 020000, CRC(5c1c3abe) SHA1(fa9f99bf7c8a6df5c71e9fd8c807f0a2ff06640d) )
	ROM_LOAD( "1818-0826-0830-03_70-revc-system_lpu.bin", 0160000, 020000, CRC(0c61a266) SHA1(0cfbf482e7f8e99c87b97c77cf178682cd7af7d6) )

	ROM_REGION( 0200000, "lpu_fast", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-1506-1502-03_00-reva-system_fast_lpu.bin", 0000000, 020000, CRC(b77194d8) SHA1(6feec8605331783e6f5a2ab6d6cbd9285036e863) )
	ROM_LOAD( "1818-1506-1502-03_10-reva-system_fast_lpu.bin", 0020000, 020000, CRC(bc5557a5) SHA1(282237e561c3f2304cdeb45efa2432748581af45) )
	ROM_LOAD( "1818-1507-1503-03_20-reva-system_fast_lpu.bin", 0040000, 020000, CRC(2ebc71e2) SHA1(a2d39fb24d565465304833dfd0ff87dd5ef26fb3) )
	ROM_LOAD( "1818-1507-1503-03_30-reva-system_fast_lpu.bin", 0060000, 020000, CRC(82e56bc4) SHA1(36201f343382e533c248ddd123507a2e195cca39) )
	ROM_LOAD( "1818-1508-1504-03_40-reva-system_fast_lpu.bin", 0100000, 020000, CRC(70b0fcb0) SHA1(3f7ce60cad0ffec8344f33d584869492c7f73026) )
	ROM_LOAD( "1818-1508-1504-03_50-reva-system_fast_lpu.bin", 0120000, 020000, CRC(935fab96) SHA1(ecb1da2a0bd46e8c0da2875a1af8cf71d8f4bb56) )
	ROM_LOAD( "1818-1509-1505-03_60-reva-system_fast_lpu.bin", 0140000, 020000, CRC(f4119af7) SHA1(72a3e8b8d7d306e55f8adf0e23225bb81bc2b4ba) )
	ROM_LOAD( "1818-1509-1505-03_70-reva-system_fast_lpu.bin", 0160000, 020000, CRC(22fb0864) SHA1(4e1dce32e84ba216dbbd4116f3b22ca7f254f529) )

	ROM_REGION( 0200000, "ppu", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-0833-0837-05_40-revc-system_ppu.bin", 0100000, 020000, CRC(d790795c) SHA1(7ba1e245a98379a34833a780898a784049e33b86) )
	ROM_LOAD( "1818-0833-0837-05_40-revd-system_ppu.bin", 0100000, 020000, CRC(49897e40) SHA1(780a9973ff26d40f470e2004fccceb1019f8ba7f) )
	ROM_LOAD( "1818-0833-0837-05_50-revc-system_ppu.bin", 0120000, 020000, CRC(ef8acde4) SHA1(e68648543aac2b841b08d7758949ba1339a83701) )
	ROM_LOAD( "1818-0833-0837-05_50-revd-system_ppu.bin", 0120000, 020000, CRC(54f61d07) SHA1(f807fb8a59cd9cd221f63907e6a86948a0bf7c1d) )
	ROM_LOAD( "1818-0834-0838-05_60-revc-system_ppu.bin", 0140000, 020000, CRC(20f2100a) SHA1(9304f0b069de9233d697588328f9657dbeabc254) )
	ROM_LOAD( "1818-0834-0838-05_60-revd-system_ppu.bin", 0140000, 020000, CRC(454af601) SHA1(54b56e67e855fd2d699a0dbef0b4d2e8c150c39b) )
	ROM_LOAD( "1818-0834-0838-05_70-revc-system_ppu.bin", 0160000, 020000, CRC(43f62491) SHA1(a9489b37b3fa8768ca6e503f346bd023833ae3ac) )
	ROM_LOAD( "1818-0834-0838-05_70-revd-system_ppu.bin", 0160000, 020000, CRC(43f62491) SHA1(a9489b37b3fa8768ca6e503f346bd023833ae3ac) )
	ROM_LOAD( "1818-1899-1898-05_60-reva-system_ppu.bin", 0140000, 020000, CRC(454af601) SHA1(54b56e67e855fd2d699a0dbef0b4d2e8c150c39b) )
	ROM_LOAD( "1818-1899-1898-05_70-reva-system_ppu.bin", 0160000, 020000, CRC(049604f2) SHA1(89bfd8e086bc9365f156966b0a62c3ac720fc627) )

	ROM_REGION( 0200000, "ppu_tops", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-0831-0835-05_00-reva-tops_ppu.bin", 0000000, 020000, CRC(7ddce706) SHA1(746e34d3de52a17372af9a9eb1ed4974a4eae656) )
	ROM_LOAD( "1818-0831-0835-05_10-reva-tops_ppu.bin", 0020000, 020000, CRC(d7fc3d47) SHA1(a3d723fe62f047cb0c17d405d07bb0b08d08e830) )
	ROM_LOAD( "1818-1209-1208-05_00-revb-tops_ppu.bin", 0000000, 020000, CRC(0dc90614) SHA1(94c07553a62b2c86414bc95314601f90eb4e4022) )
	ROM_LOAD( "1818-1209-1208-05_10-revb-tops_ppu.bin", 0020000, 020000, CRC(4e362657) SHA1(b09098c0acd56b11ec3b72ff3e8b5a1e14ef3ae8) )
	ROM_LOAD( "1818-1592-1591-05_00-revb-tops_ppu.bin", 0000000, 020000, CRC(8cfe29a8) SHA1(f1007b6b1d3f2b603653880c44cec48b23701263) )
	ROM_LOAD( "1818-1592-1591-05_10-revb-tops_ppu.bin", 0020000, 020000, CRC(95048264) SHA1(36cfddef9d1289fdaf69596e10d95f88a520feae) )

	ROM_REGION( 0200000, "ppu_kbd_us", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-0832-0836-05_20-revc-keyboard_us.bin", 0040000, 020000, CRC(3bf6268a) SHA1(65d7dfeaf34c74dbc86ebe5d3bb65c6bd10163cb) )
	ROM_LOAD( "1818-0832-0836-05_30-revc-keyboard_us.bin", 0060000, 020000, CRC(2dfc619c) SHA1(5c54ff502d1344907817210bfdfcab7f8d6b61bd) )

	ROM_REGION( 0200000, "ppu_kbd_de", ROMREGION_16BIT | ROMREGION_BE )
	ROM_LOAD( "1818-0841-0846-05_20-revc-keyboard_german.bin", 0040000, 020000, CRC(76667eca) SHA1(ac63e5d584d1f2da5668d8a9560f927f48e25e03) )
	ROM_LOAD( "1818-0841-0846-05_20-revd-keyboard_german.bin", 0060000, 020000, CRC(3bf6268a) SHA1(65d7dfeaf34c74dbc86ebe5d3bb65c6bd10163cb) )
	ROM_LOAD( "1818-0841-0846-05_30-revc-keyboard_german.bin", 0040000, 020000, CRC(2b83db22) SHA1(6eda714ce05d2d75f4c041e36b6b6df40697d94a) )
	ROM_LOAD( "1818-0841-0846-05_30-revd-keyboard_german.bin", 0060000, 020000, CRC(b4006959) SHA1(584a85f746a3b0c262fdf9e4be8e696c80cfd429) )
#endif
ROM_END

#define rom_hp9845t rom_hp9845b
#define rom_hp9845c rom_hp9845b

COMP( 1978, hp9845a,   0,       0,      hp9845a,       hp9845, driver_device, 0,      "Hewlett-Packard",  "9845A",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
COMP( 1978, hp9845s,   hp9845a, 0,      hp9845a,       hp9845, driver_device, 0,      "Hewlett-Packard",  "9845S",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
COMP( 1979, hp9835a,   0,       0,      hp9835a,       hp9845, driver_device, 0,      "Hewlett-Packard",  "9835A",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
COMP( 1979, hp9835b,   hp9835a, 0,      hp9835a,       hp9845, driver_device, 0,      "Hewlett-Packard",  "9835B",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
COMP( 1980, hp9845b,   0,       0,      hp9845b,       hp9845b,driver_device, 0,      "Hewlett-Packard",  "9845B",  0 )
COMP( 1980, hp9845t,   hp9845b, 0,      hp9845b,       hp9845b,driver_device, 0,      "Hewlett-Packard",  "9845T",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
COMP( 1981, hp9845c,   hp9845b, 0,      hp9845b,       hp9845b,driver_device, 0,      "Hewlett-Packard",  "9845C",  MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND )